diff --git a/django/db/models/sql/constants.py b/django/db/models/sql/constants.py
index 63c704f..1a2cc72 100644
--- a/django/db/models/sql/constants.py
+++ b/django/db/models/sql/constants.py
@@ -7,6 +7,12 @@ QUERY_TERMS = dict([(x, None) for x in (
     'month', 'day', 'week_day', 'isnull', 'search', 'regex', 'iregex',
     )])
 
+# Valid query types for related fields.
+# See `django.db.models.fields.related.RelatedField.get_db_prep_lookup`.
+RELATED_QUERY_TERMS = dict([(x, None) for x in (
+    'exact', 'gt', 'lt', 'gte', 'lte', 'range', 'in', 'isnull'
+    )])
+
 # Size of each "chunk" for get_iterator calls.
 # Larger values are slightly faster at the expense of more storage space.
 GET_ITERATOR_CHUNK_SIZE = 100
diff --git a/django/db/models/sql/query.py b/django/db/models/sql/query.py
index 9a19a9e..d9f357b 100644
--- a/django/db/models/sql/query.py
+++ b/django/db/models/sql/query.py
@@ -77,6 +77,7 @@ class Query(object):
 
     alias_prefix = 'T'
     query_terms = QUERY_TERMS
+    related_query_terms = RELATED_QUERY_TERMS
     aggregates_module = base_aggregates_module
 
     compiler = 'SQLCompiler'
@@ -953,10 +954,30 @@ class Query(object):
             raise FieldError("Cannot parse keyword query %r" % arg)
 
         # Work out the lookup type and remove it from 'parts', if necessary.
-        if len(parts) == 1 or parts[-1] not in self.query_terms:
+        if len(parts) == 1:
             lookup_type = 'exact'
         else:
-            lookup_type = parts.pop()
+            # Find the last field in the lookup and determine if it's a
+            # related field. By restricting the query terms used for lookups
+            # that span relations, we prevent valid field names like "year"
+            # from being misinterpreted as lookup types.
+            try:
+                lookup_model = self.model
+                for field_name in parts[:-1]:
+                    lookup_field = lookup_model._meta.get_field(field_name)
+                    if lookup_field.rel:
+                        lookup_model = lookup_field.rel.to
+            except FieldDoesNotExist:
+                query_terms = self.query_terms
+            else:
+                if lookup_field.rel:
+                    query_terms = self.related_query_terms
+                else:
+                    query_terms = self.query_terms
+            if parts[-1] in query_terms:
+                lookup_type = parts.pop()
+            else:
+                lookup_type = 'exact'
 
         # By default, this is a WHERE clause. If an aggregate is referenced
         # in the value, the filter will be promoted to a HAVING
diff --git a/tests/regressiontests/model_related_lookups_regress/__init__.py b/tests/regressiontests/model_related_lookups_regress/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/tests/regressiontests/model_related_lookups_regress/models.py b/tests/regressiontests/model_related_lookups_regress/models.py
new file mode 100644
index 0000000..97d12cf
--- /dev/null
+++ b/tests/regressiontests/model_related_lookups_regress/models.py
@@ -0,0 +1,81 @@
+from django.db import models
+
+
+class Season(models.Model):
+    year = models.PositiveSmallIntegerField()
+    world_series_winner = models.CharField(max_length=100)
+
+    def __unicode__(self):
+        return unicode(self.year)
+
+
+class Game(models.Model):
+    season = models.ForeignKey(Season, related_name='games')
+    home = models.CharField(max_length=100)
+    away = models.CharField(max_length=100)
+
+    def __unicode__(self):
+        return u"%s at %s" % (self.away, self.home)
+
+
+class Player(models.Model):
+    name = models.CharField(max_length=100)
+    games = models.ManyToManyField(Game, related_name='players')
+
+    def __unicode__(self):
+        return self.name
+
+
+__test__ = {'API_TESTS':"""
+Regression test for #11670
+
+>>> season_2009 = Season.objects.create(year=2009, world_series_winner="New York Yankees")
+>>> cardinals_at_astros = season_2009.games.create(home="Houston Astros", away="St. Louis Cardinals")
+
+>>> season_2010 = Season.objects.create(year=2010, world_series_winner="Houston Astros")
+>>> cubs_at_astros = season_2010.games.create(home="Houston Astros", away="Chicago Cubs")
+>>> brewers_at_astros = season_2010.games.create(home="Houston Astros", away="Milwaukee Brewers")
+
+>>> Game.objects.count()
+3
+
+>>> Game.objects.filter(season__year=2010).count()
+2
+
+>>> Game.objects.get(season__year=2009)
+<Game: St. Louis Cardinals at Houston Astros>
+
+>>> hunter_pence = Player.objects.create(name="Hunter Pence")
+>>> hunter_pence.games = Game.objects.filter(season__year__in=[2009, 2010])
+
+>>> hunter_pence.games.count()
+3
+
+>>> hunter_pence.games.filter(season__year=2009).count()
+1
+
+>>> hunter_pence.games.filter(season__year__exact=2010).count()
+2
+
+>>> pudge = Player.objects.create(name="Ivan Rodriquez")
+>>> pudge.games = Game.objects.filter(season__year=2009)
+
+>>> pedro_feliz = Player.objects.create(name="Pedro Feliz")
+>>> pedro_feliz.games = Game.objects.filter(season__year=2010)
+
+>>> Player.objects.count()
+3
+
+>>> Player.objects.filter(games__season__year=2009).distinct().count()
+2
+
+>>> Player.objects.filter(games__season__year__exact=2010).distinct().count()
+2
+
+>>> Player.objects.filter(games__season__world_series_winner__icontains="Yankees").distinct().count()
+2
+
+>>> Player.objects.filter(games__season__world_series_winner__iexact="Houston Astros").distinct().count()
+2
+
+"""}
