diff --git a/esqueleto.cabal b/esqueleto.cabal
--- a/esqueleto.cabal
+++ b/esqueleto.cabal
@@ -1,5 +1,5 @@
 name:                esqueleto
-version:             2.4.2
+version:             2.4.3
 synopsis:            Type-safe EDSL for SQL queries on persistent backends.
 homepage:            https://github.com/prowdsponsor/esqueleto
 license:             BSD3
diff --git a/src/Database/Esqueleto.hs b/src/Database/Esqueleto.hs
--- a/src/Database/Esqueleto.hs
+++ b/src/Database/Esqueleto.hs
@@ -52,7 +52,8 @@
              , subList_select, subList_selectDistinct, valList, justList
              , in_, notIn, exists, notExists
              , set, (=.), (+=.), (-=.), (*=.), (/=.)
-             , case_ )
+             , case_, toBaseId)
+  , ToBaseId(..)
   , when_
   , then_
   , else_
diff --git a/src/Database/Esqueleto/Internal/Language.hs b/src/Database/Esqueleto/Internal/Language.hs
--- a/src/Database/Esqueleto/Internal/Language.hs
+++ b/src/Database/Esqueleto/Internal/Language.hs
@@ -32,6 +32,7 @@
   , Insertion
   , LockingKind(..)
   , SqlString
+  , ToBaseId(..)
     -- * The guts
   , JoinKind(..)
   , IsJoinKind(..)
@@ -555,6 +556,42 @@
   -- /Since: 2.1.2/
   case_ :: PersistField a => [(expr (Value Bool), expr (Value a))] -> expr (Value a) -> expr (Value a)
 
+  -- | Convert an entity's key into another entity's.
+  --
+  -- This function is to be used when you change an entity's @Id@ to be
+  -- that of another entity.  For example:
+  --
+  -- @
+  -- Bar
+  --   barNum Int
+  -- Foo
+  --   Id BarId
+  --   fooNum Int
+  -- @
+  --
+  -- For this example, declare:
+  --
+  -- @
+  -- instance ToBaseId Foo where
+  --   type BaseEnt Foo = Bar
+  --   toBaseIdWitness = FooKey
+  -- @
+  --
+  -- Now you're able to write queries such as:
+  --
+  -- @
+  -- 'select' $
+  -- 'from' $ \(bar `'InnerJoin`` foo) -> do
+  -- 'on' ('toBaseId' (foo '^.' FooId) '==.' bar '^.' BarId)
+  -- return (bar, foo)
+  -- @
+  --
+  -- Note: this function may be unsafe to use in conditions not like the
+  -- one of the example above.
+  --
+  -- /Since: 2.4.3/
+  toBaseId :: ToBaseId ent => expr (Value (Key ent)) -> expr (Value (Key (BaseEnt ent)))
+
 {-# DEPRECATED sub_selectDistinct "Since 2.2.4: use 'sub_select' and 'distinct'." #-}
 {-# DEPRECATED subList_selectDistinct "Since 2.2.4: use 'subList_select' and 'distinct'." #-}
 
@@ -836,6 +873,12 @@
 
 -- | /Since: 2.4.0/
 instance SqlString a => SqlString (Maybe a) where
+
+-- | Class that enables one to use 'toBaseId' to convert an entity's
+-- key on a query into another (cf. 'toBaseId').
+class ToBaseId ent where
+  type BaseEnt ent :: *
+  toBaseIdWitness :: Key (BaseEnt ent) -> Key ent
 
 
 -- | @FROM@ clause: bring entities into scope.
diff --git a/src/Database/Esqueleto/Internal/Sql.hs b/src/Database/Esqueleto/Internal/Sql.hs
--- a/src/Database/Esqueleto/Internal/Sql.hs
+++ b/src/Database/Esqueleto/Internal/Sql.hs
@@ -524,6 +524,8 @@
   (EInsert _ _) <&> (ECompositeKey _) = unexpectedCompositeKeyError "(<&>)"
 
   case_ = unsafeSqlCase
+  toBaseId = veryUnsafeCoerceSqlExprValue
+
 
 instance ToSomeValues SqlExpr (SqlExpr (Value a)) where
   toSomeValues a = [SomeValue a]
