diff --git a/django/db/models/options.py b/django/db/models/options.py
index 7308a15..540b505 100644
--- a/django/db/models/options.py
+++ b/django/db/models/options.py
@@ -478,7 +478,7 @@ class Options(object):
             result.update(parent._meta.get_parent_list())
         return result
 
-    def get_ancestor_link(self, ancestor):
+    def get_ancestor_link(self, ancestor,grandparents=True):
         """
         Returns the field on the current model which points to the given
         "ancestor". This is possible an indirect link (a pointer to a parent
@@ -489,6 +489,8 @@ class Options(object):
         """
         if ancestor in self.parents:
             return self.parents[ancestor]
+        if not grandparents:
+          return None
         for parent in self.parents:
             # Tries to get a link field from the immediate parent
             parent_link = parent._meta.get_ancestor_link(ancestor)
diff --git a/django/db/models/sql/query.py b/django/db/models/sql/query.py
index 53dad60..df9da5c 100644
--- a/django/db/models/sql/query.py
+++ b/django/db/models/sql/query.py
@@ -877,6 +877,7 @@ class Query(object):
         If 'nullable' is True, the join can potentially involve NULL values and
         is a candidate for promotion (to "left outer") when combining querysets.
         """
+        
         lhs, table, lhs_col, col = connection
         if lhs in self.alias_map:
             lhs_table = self.alias_map[lhs].table_name
@@ -938,11 +939,33 @@ class Query(object):
         root_alias = self.tables[0]
         seen = {None: root_alias}
 
-        for field, model in opts.get_fields_with_model():
-            if model not in seen:
-                link_field = opts.get_ancestor_link(model)
-                seen[model] = self.join((root_alias, model._meta.db_table,
-                        link_field.column, model._meta.pk.column))
+        ancestors = []
+        redo = [i for i in opts.get_fields_with_model()]
+        todo = []
+
+        # We maintain a list of things todo, and models we coudn't link from this
+        # for the next.  If the lenth of both is the same, the previous loop didn't
+        # Link anything, let's bail so we don't end up with an endless loop
+        while len(redo) > 0 and len(redo) != len(todo):
+            todo = redo
+            redo = []
+            for field, model in todo:
+                link_field = None
+                if model not in seen:
+                    link_field = opts.get_ancestor_link(model,grandparents=False)
+                    if link_field:
+                        seen[model] = self.join((root_alias, model._meta.db_table,link_field.column, model._meta.pk.column))
+                        ancestors.append(model)
+                    else: # we didn't link this model to our curent model, try the ancestors
+                        for ancestor in ancestors:
+                            link_field = ancestor._meta.concrete_model._meta.get_ancestor_link(model,grandparents=False)
+                            if link_field:
+                                seen[model] = self.join((ancestor._meta.db_table, model._meta.db_table,link_field.column, model._meta.pk.column))
+                                ancestors.append(model)
+                                break
+                    if not link_field: # didn't find it in the ancestors either, add it to the list to try next time
+                       redo.append((field, model))
+
         self.included_inherited_models = seen
 
     def remove_inherited_models(self):
diff --git a/tests/regressiontests/queries/models.py b/tests/regressiontests/queries/models.py
index 6328776..2eda9e5 100644
--- a/tests/regressiontests/queries/models.py
+++ b/tests/regressiontests/queries/models.py
@@ -358,3 +358,32 @@ class NullableName(models.Model):
 
     class Meta:
         ordering = ['id']
+
+
+class Base1(models.Model):
+    b1_id = models.AutoField(primary_key=True)
+    b1_desc = models.CharField(max_length=100, null=True)
+
+class Base2(models.Model):
+    b2_id = models.AutoField(primary_key=True)
+    b2_desc = models.CharField(max_length=100, null=True)
+
+class Base3(models.Model):
+    b3_id = models.AutoField(primary_key=True)
+    b3_desc = models.CharField(max_length=100, null=True)
+
+class Middle(Base1, Base2, Base3):
+    m_desc = models.CharField(max_length=100, null=True)
+
+class Top(Middle):
+    t_desc = models.CharField(max_length=100)
+
+class Top2(Top):
+    t2_desc = models.CharField(max_length=100)
+
+class Top3(Top2):
+    t3_desc = models.CharField(max_length=100)
+
+class Top4(Top3):
+    t4_desc = models.CharField(max_length=100)
+
diff --git a/tests/regressiontests/queries/tests.py b/tests/regressiontests/queries/tests.py
index 1582993..03fe879 100644
--- a/tests/regressiontests/queries/tests.py
+++ b/tests/regressiontests/queries/tests.py
@@ -23,7 +23,7 @@ from .models import (Annotation, Article, Author, Celebrity, Child, Cover,
     Ranking, Related, Report, ReservedName, Tag, TvChef, Valid, X, Food, Eaten,
     Node, ObjectA, ObjectB, ObjectC, CategoryItem, SimpleCategory,
     SpecialCategory, OneToOneCategory, NullableName, ProxyCategory,
-    SingleObject, RelatedObject)
+    SingleObject, RelatedObject, Top, Base1, Top2, Top3, Top4)
 
 
 class BaseQuerysetTest(TestCase):
@@ -847,6 +847,24 @@ class Queries1Tests(BaseQuerysetTest):
         )
         Tag._meta.ordering = original_ordering
 
+    def test_ticket18174(self):
+        """
+        Check that in a model like this:
+                         / Base1
+            Top -> Middle- Base2
+                         \ Base3
+
+        The joins are done from Top to Middle to Base1, Base2, Base3.
+        """
+        Base1.objects.create()
+        Top.objects.create(t_desc='foo')
+        qs = Top.objects.all()
+        # The joins to the parent tables are added only when the query is
+        # evaluated.
+        results = list(qs)
+        self.assertEqual(qs.query.alias_map['queries_base1'].lhs_alias, 'queries_middle')
+        self.assertEqual(len(results), 1)
+
     def test_exclude(self):
         self.assertQuerysetEqual(
             Item.objects.exclude(tags__name='t4'),
@@ -880,6 +898,27 @@ class Queries1Tests(BaseQuerysetTest):
             Item.objects.filter(Q(tags__name__in=['t4', 't3'])),
             [repr(i) for i in Item.objects.filter(~~Q(tags__name__in=['t4', 't3']))])
 
+
+    def test_ticket18174_2(self):
+        """
+        Check that in a model like this:
+                                                 / Base1
+            Top4 -> Top3 -> Top2 -> Top -> Middle- Base2
+                                                 \ Base3
+
+        The joins are done from Top to Middle to Base1, Base2, Base3.
+        Adding Extra Grandparents to make sure the chaning to the top works.
+        """
+        Base1.objects.create()
+        Top4.objects.create(t_desc='foo')
+        qs = Top4.objects.all()
+        # The joins to the parent tables are added only when the query is
+        # evaluated.
+        results = list(qs)
+        self.assertEqual(qs.query.alias_map['queries_base1'].lhs_alias, 'queries_middle')
+        self.assertEqual(len(results), 1)
+
+
 class Queries2Tests(TestCase):
     def setUp(self):
         Number.objects.create(num=4)
