diff --git a/django/db/models/query.py b/django/db/models/query.py
index b21db2e..cb79382 100644
--- a/django/db/models/query.py
+++ b/django/db/models/query.py
@@ -23,6 +23,10 @@ REPR_OUTPUT_SIZE = 20
 # Pull into this namespace for backwards compatibility.
 EmptyResultSet = sql.EmptyResultSet
 
+# Maximum amount of prefetch related queries to be done when evaluating
+# a single queryset.
+MAX_PREFETCH_PER_QUERY = 100
+
 class QuerySet(object):
     """
     Represents a lazy database lookup for a set of objects.
@@ -1578,6 +1582,12 @@ def prefetch_related_objects(result_cache, related_lookups):
 
     # We may expand related_lookups, so need a loop that allows for that
     for lookup in related_lookups:
+        if len(done_queries) > MAX_PREFETCH_PER_QUERY:
+            raise ValueError(
+                'Over %s prefetch_related lookups in one query. '
+                'Likely reason is recursion caused by default managers'
+                % MAX_PREFETCH_PER_QUERY
+            )
         if lookup in done_lookups:
             # We've done exactly this already, skip the whole thing
             continue
diff --git a/tests/modeltests/prefetch_related/models.py b/tests/modeltests/prefetch_related/models.py
index ab28496..8ea01a0 100644
--- a/tests/modeltests/prefetch_related/models.py
+++ b/tests/modeltests/prefetch_related/models.py
@@ -163,3 +163,66 @@ class Employee(models.Model):
 
     class Meta:
         ordering = ['id']
+
+class RecursiveManager(models.Manager):
+    def get_query_set(self):
+        return (super(RecursiveManager, self).get_query_set()
+                .prefetch_related('recurse_reverse'))
+
+class RecursiveRel(models.Model):
+    val = models.TextField()
+    recursion = models.ForeignKey('self', related_name='recurse_reverse', null=True)
+    objects = RecursiveManager()
+
+"""
+Construct a nasty diamond strucure of models,
+connected by default managers:
+       B
+      / \
+     /   \
+    /     \
+   A <---- D
+    \     /
+     \   /
+      \ /
+       C
+
+Contains two loops:
+A -> C -> D -> A
+A -> B -> D -> A
+
+In addition, C -> D and B -> D have same accessor name, d_set
+"""
+
+class AManager(models.Manager):
+    def get_query_set(self):
+        return super(AManager, self).get_query_set().prefetch_related('b_set', 'c_set')
+
+class BManager(models.Manager):
+    def get_query_set(self):
+        return super(BManager, self).get_query_set().prefetch_related('d_set')
+
+class CManager(models.Manager):
+    def get_query_set(self):
+        return super(CManager, self).get_query_set().prefetch_related('d_set')
+
+class DManager(models.Manager):
+    def get_query_set(self):
+        return super(CManager, self).get_query_set().prefetch_related('a_set')
+
+class DiamondA(models.Model):
+    d = models.ForeignKey('DiamondD', null=True)
+    objects = AManager()
+
+class DiamondB(models.Model):
+    a = models.ForeignKey(DiamondA, null=True)
+    objects = BManager()
+
+class DiamondC(models.Model):
+    a = models.ForeignKey(DiamondA, null=True)
+    objects = CManager()
+
+class DiamondD(models.Model):
+    b = models.ForeignKey(DiamondB, null=True)
+    c = models.ForeignKey(DiamondC, null=True) 
+    objects = DManager()
diff --git a/tests/modeltests/prefetch_related/tests.py b/tests/modeltests/prefetch_related/tests.py
index 45202f2..c991fc3 100644
--- a/tests/modeltests/prefetch_related/tests.py
+++ b/tests/modeltests/prefetch_related/tests.py
@@ -7,7 +7,8 @@ from django.utils import unittest
 from models import (Author, Book, Reader, Qualification, Teacher, Department,
                     TaggedItem, Bookmark, AuthorAddress, FavoriteAuthors,
                     AuthorWithAge, BookWithYear, Person, House, Room,
-                    Employee)
+                    Employee, RecursiveRel, DiamondA, DiamondB, DiamondC,
+                    DiamondD)
 
 
 class PrefetchRelatedTests(TestCase):
@@ -416,3 +417,26 @@ class NullableTest(TestCase):
                         for e in qs2]
 
         self.assertEqual(co_serfs, co_serfs2)
+
+
+class RecursionTest(TestCase):
+    def setUp(self):
+        r1 = RecursiveRel.objects.create(val='foo')
+        r2 = RecursiveRel.objects.create(val='foo', recursion=r1)
+        r1.recursion = r2
+        r1.save()
+
+    def test_recursion(self):
+        RecursiveRel.objects.all()[0]
+
+class DiamondTest(TestCase):
+    def setUp(self):
+        a = DiamondA.objects.create()
+        b = DiamondB.objects.create(a=a)
+        c = DiamondA.objects.create(a=a)
+        d = DiamondA.objects.create(b=b, c=c)
+        a.d = d
+        a.save()
+
+    def test_diamond_recusion(self):
+        DiamondA.objects.all()[0]
