diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,3 +1,8 @@
+## 2.7.2
+
+* Expose the knot tying logic of `parseReferences` so that users can build
+  migrations from independently define entities at runtime [#932](https://github.com/yesodweb/persistent/pull/932)
+
 ## 2.7.1
 
 * Add the `mkEntityDefList` function to work around [#902](https://github.com/yesodweb/persistent/issues/902). [#904](https://github.com/yesodweb/persistent/pull/904)
diff --git a/Database/Persist/TH.hs b/Database/Persist/TH.hs
--- a/Database/Persist/TH.hs
+++ b/Database/Persist/TH.hs
@@ -40,6 +40,7 @@
       -- * Internal
     , lensPTH
     , parseReferences
+    , embedEntityDefs
     , AtLeastOneUniqueKey(..)
     , OnlyOneUniqueKey(..)
     ) where
@@ -164,14 +165,20 @@
       s <- qRunIO $ TIO.hGetContents h
       return s
 
--- calls parse to Quasi.parse individual entities in isolation
--- afterwards, sets references to other entities
--- | @since 2.5.3
-parseReferences :: PersistSettings -> Text -> Q Exp
-parseReferences ps s = lift $
-     map (mkEntityDefSqlTypeExp embedEntityMap entMap) noCycleEnts
+-- Takes a list of (potentially) independently defined entities and properly
+-- links all foreign keys to reference the right 'EntityDef', tying the knot
+-- between entities.
+--
+-- Allows users to define entities indepedently or in separate modules and then
+-- fix the cross-references between them at runtime to create a 'Migration'.
+--
+-- @since 2.7.2
+embedEntityDefs :: [EntityDef] -> [EntityDef]
+embedEntityDefs = snd . embedEntityDefsMap
+
+embedEntityDefsMap :: [EntityDef] -> (M.Map HaskellName EmbedEntityDef, [EntityDef])
+embedEntityDefsMap rawEnts = (embedEntityMap, noCycleEnts)
   where
-    entMap = M.fromList $ map (\ent -> (entityHaskell ent, ent)) noCycleEnts
     noCycleEnts = map breakCycleEnt entsWithEmbeds
     -- every EntityDef could reference each-other (as an EmbedRef)
     -- let Haskell tie the knot
@@ -180,7 +187,6 @@
     setEmbedEntity ent = ent
       { entityFields = map (setEmbedField (entityHaskell ent) embedEntityMap) $ entityFields ent
       }
-    rawEnts = parse ps s
 
     -- self references are already broken
     -- look at every emFieldEmbed to see if it refers to an already seen HaskellName
@@ -208,6 +214,15 @@
       where
         membed = emFieldEmbed emf
 
+-- calls parse to Quasi.parse individual entities in isolation
+-- afterwards, sets references to other entities
+-- | @since 2.5.3
+parseReferences :: PersistSettings -> Text -> Q Exp
+parseReferences ps s = lift $
+     map (mkEntityDefSqlTypeExp embedEntityMap entMap) noCycleEnts
+  where
+    (embedEntityMap, noCycleEnts) = embedEntityDefsMap $ parse ps s
+    entMap = M.fromList $ map (\ent -> (entityHaskell ent, ent)) noCycleEnts
 
 
 stripId :: FieldType -> Maybe Text
diff --git a/persistent-template.cabal b/persistent-template.cabal
--- a/persistent-template.cabal
+++ b/persistent-template.cabal
@@ -1,5 +1,5 @@
 name:            persistent-template
-version:         2.7.1
+version:         2.7.2
 license:         MIT
 license-file:    LICENSE
 author:          Michael Snoyman <michael@snoyman.com>
