diff --git a/django/contrib/admin/options.py b/django/contrib/admin/options.py
index cef9021326..3d0faf0e33 100644
--- a/django/contrib/admin/options.py
+++ b/django/contrib/admin/options.py
@@ -450,9 +450,9 @@ class BaseModelAdmin(six.with_metaclass(RenameBaseModelAdminMethods)):
         except FieldDoesNotExist:
             return False
 
-        # Check whether this model is the origin of a M2M relationship
-        # in which case to_field has to be the pk on this model.
-        if opts.many_to_many and field.primary_key:
+        # Always allow referencing the primary key since it's already possible
+        # to get this information from the change view URL.
+        if field.primary_key:
             return True
 
         # Make sure at least one of the models registered for this site
@@ -463,8 +463,7 @@ class BaseModelAdmin(six.with_metaclass(RenameBaseModelAdminMethods)):
             for inline in admin.inlines:
                 registered_models.add(inline.model)
 
-        for related_object in (opts.get_all_related_objects(include_hidden=True) +
-                               opts.get_all_related_many_to_many_objects()):
+        for related_object in opts.get_all_related_objects(include_hidden=True):
             related_model = related_object.model
             if (any(issubclass(model, related_model) for model in registered_models) and
                     related_object.field.rel.get_related_field() == field):
diff --git a/docs/releases/1.4.17.txt b/docs/releases/1.4.17.txt
index f8785bcea2..6279941733 100644
--- a/docs/releases/1.4.17.txt
+++ b/docs/releases/1.4.17.txt
@@ -4,7 +4,14 @@ Django 1.4.17 release notes
 
 *Under development*
 
-Django 1.4.17 ...
+Django 1.4.17 fixes a regression in the 1.4.14 security release.
 
 Additionally, Django's vendored version of six, :mod:`django.utils.six`, has
 been upgraded to the latest release (1.8.0).
+
+Bugfixes
+========
+
+* Fixed a regression with dynamically generated inlines and allowed field
+  references in the admin
+  (`#23754 <http://code.djangoproject.com/ticket/23754>`_).
diff --git a/docs/releases/1.5.12.txt b/docs/releases/1.5.12.txt
new file mode 100644
index 0000000000..a1107bedfa
--- /dev/null
+++ b/docs/releases/1.5.12.txt
@@ -0,0 +1,14 @@
+===========================
+Django 1.5.12 release notes
+===========================
+
+*Under development*
+
+Django 1.5.12 fixes a regression in the 1.5.9 security release.
+
+Bugfixes
+========
+
+* Fixed a regression with dynamically generated inlines and allowed field
+  references in the admin
+  (`#23754 <http://code.djangoproject.com/ticket/23754>`_).
diff --git a/docs/releases/1.6.9.txt b/docs/releases/1.6.9.txt
index 242894229a..08f943fa51 100644
--- a/docs/releases/1.6.9.txt
+++ b/docs/releases/1.6.9.txt
@@ -4,7 +4,13 @@ Django 1.6.9 release notes
 
 *Under development*
 
-Django 1.6.9 ...
+Django 1.6.9 fixes a regression in the 1.6.6 security release.
 
 Additionally, Django's vendored version of six, :mod:`django.utils.six`, has
 been upgraded to the latest release (1.8.0).
+
+Bugfixes
+========
+
+* Fixed a regression with dynamically generated inlines and allowed field
+  references in the admin (:ticket:`23754`).
diff --git a/docs/releases/1.7.2.txt b/docs/releases/1.7.2.txt
index 1465db5def..e94b14dad2 100644
--- a/docs/releases/1.7.2.txt
+++ b/docs/releases/1.7.2.txt
@@ -83,3 +83,6 @@ Bugfixes
 
 * Added missing context to the admin's ``delete_selected`` view that prevented
   custom site header, etc. from appearing (:ticket:`23898`).
+
+* Fixed a regression with dynamically generated inlines and allowed field
+  references in the admin (:ticket:`23754`).
diff --git a/docs/releases/index.txt b/docs/releases/index.txt
index a587ae2c64..5f8fa675ac 100644
--- a/docs/releases/index.txt
+++ b/docs/releases/index.txt
@@ -50,6 +50,7 @@ versions of the documentation contain the release notes for any later releases.
 .. toctree::
    :maxdepth: 1
 
+   1.5.12
    1.5.11
    1.5.10
    1.5.9
diff --git a/tests/admin_views/admin.py b/tests/admin_views/admin.py
index 8e6cd251e2..964ea83599 100644
--- a/tests/admin_views/admin.py
+++ b/tests/admin_views/admin.py
@@ -36,8 +36,8 @@ from .models import (Article, Chapter, Child, Parent, Picture, Widget,
     FilteredManager, EmptyModelHidden, EmptyModelVisible, EmptyModelMixin,
     State, City, Restaurant, Worker, ParentWithDependentChildren,
     DependentChild, StumpJoke, FieldOverridePost, FunkyTag,
-    ReferencedByParent, ChildOfReferer, M2MReference, ReferencedByInline,
-    InlineReference, InlineReferer, Ingredient)
+    ReferencedByParent, ChildOfReferer, ReferencedByInline,
+    InlineReference, InlineReferer, Recipe, Ingredient, NotReferenced)
 
 
 def callable_year(dt_value):
@@ -893,7 +893,6 @@ site.register(Worker, WorkerAdmin)
 site.register(FunkyTag, FunkyTagAdmin)
 site.register(ReferencedByParent)
 site.register(ChildOfReferer)
-site.register(M2MReference)
 site.register(ReferencedByInline)
 site.register(InlineReferer, InlineRefererAdmin)
 
@@ -932,7 +931,9 @@ site.register(EmptyModelHidden, EmptyModelHiddenAdmin)
 site.register(EmptyModelVisible, EmptyModelVisibleAdmin)
 site.register(EmptyModelMixin, EmptyModelMixinAdmin)
 site.register(StumpJoke)
+site.register(Recipe)
 site.register(Ingredient)
+site.register(NotReferenced)
 
 # Register core models we need in our tests
 from django.contrib.auth.models import User, Group
diff --git a/tests/admin_views/models.py b/tests/admin_views/models.py
index 0d61ba3fbb..9d5b49c89f 100644
--- a/tests/admin_views/models.py
+++ b/tests/admin_views/models.py
@@ -826,28 +826,28 @@ class Worker(models.Model):
 
 # Models for #23329
 class ReferencedByParent(models.Model):
-    pass
+    name = models.CharField(max_length=20, unique=True)
 
 
 class ParentWithFK(models.Model):
-    fk = models.ForeignKey(ReferencedByParent)
+    fk = models.ForeignKey(
+        ReferencedByParent, to_field='name', related_name='hidden+',
+    )
 
 
 class ChildOfReferer(ParentWithFK):
     pass
 
 
-class M2MReference(models.Model):
-    ref = models.ManyToManyField('self')
-
-
 # Models for #23431
 class ReferencedByInline(models.Model):
-    pass
+    name = models.CharField(max_length=20, unique=True)
 
 
 class InlineReference(models.Model):
-    fk = models.ForeignKey(ReferencedByInline, related_name='hidden+')
+    fk = models.ForeignKey(
+        ReferencedByInline, to_field='name', related_name='hidden+',
+    )
 
 
 class InlineReferer(models.Model):
@@ -856,9 +856,14 @@ class InlineReferer(models.Model):
 
 # Models for #23604
 class Recipe(models.Model):
-    name = models.CharField(max_length=20)
+    pass
 
 
 class Ingredient(models.Model):
-    name = models.CharField(max_length=20)
-    recipes = models.ManyToManyField('Recipe', related_name='ingredients')
+    recipes = models.ManyToManyField(Recipe)
+
+
+# Model for #23839
+class NotReferenced(models.Model):
+    # Don't point any FK at this model.
+    pass
diff --git a/tests/admin_views/tests.py b/tests/admin_views/tests.py
index 2c7db8bd6b..50d68df2a2 100644
--- a/tests/admin_views/tests.py
+++ b/tests/admin_views/tests.py
@@ -613,26 +613,30 @@ class AdminViewBasicTest(AdminViewBasicTestCase):
             self.assertEqual(response.status_code, 400)
             self.assertEqual(len(calls), 1)
 
-        # Specifying a field referenced by another model should be allowed.
-        response = self.client.get("/test_admin/admin/admin_views/section/", {TO_FIELD_VAR: 'id'})
+        # #23839 - Primary key should always be allowed, even if the referenced model isn't registered.
+        response = self.client.get("/test_admin/admin/admin_views/notreferenced/", {TO_FIELD_VAR: 'id'})
         self.assertEqual(response.status_code, 200)
 
         # Specifying a field referenced by another model though a m2m should be allowed.
-        response = self.client.get("/test_admin/admin/admin_views/m2mreference/", {TO_FIELD_VAR: 'id'})
+        # XXX: We're not testing against a non-primary key field since the admin doesn't
+        # support it yet, ref #23862
+        response = self.client.get("/test_admin/admin/admin_views/recipe/", {TO_FIELD_VAR: 'id'})
         self.assertEqual(response.status_code, 200)
 
-        # #23604 - Specifying the pk of this model should be allowed when this model defines a m2m relationship
+        # #23604 - Specifying a field referenced through a reverse m2m relationship should be allowed.
+        # XXX: We're not testing against a non-primary key field since the admin doesn't
+        # support it yet, ref #23862
         response = self.client.get("/test_admin/admin/admin_views/ingredient/", {TO_FIELD_VAR: 'id'})
         self.assertEqual(response.status_code, 200)
 
         # #23329 - Specifying a field that is not referred by any other model directly registered
         # to this admin site but registered through inheritance should be allowed.
-        response = self.client.get("/test_admin/admin/admin_views/referencedbyparent/", {TO_FIELD_VAR: 'id'})
+        response = self.client.get("/test_admin/admin/admin_views/referencedbyparent/", {TO_FIELD_VAR: 'name'})
         self.assertEqual(response.status_code, 200)
 
         # #23431 - Specifying a field that is only referred to by a inline of a registered
         # model should be allowed.
-        response = self.client.get("/test_admin/admin/admin_views/referencedbyinline/", {TO_FIELD_VAR: 'id'})
+        response = self.client.get("/test_admin/admin/admin_views/referencedbyinline/", {TO_FIELD_VAR: 'name'})
         self.assertEqual(response.status_code, 200)
 
         # We also want to prevent the add and change view from leaking a