diff --git a/django/db/models/base.py b/django/db/models/base.py
index 71fd1f7..42efe54 100644
--- a/django/db/models/base.py
+++ b/django/db/models/base.py
@@ -129,7 +129,12 @@ class ModelBase(type):
         # Do the appropriate setup for any model parents.
         o2o_map = dict([(f.rel.to, f) for f in new_class._meta.local_fields
                 if isinstance(f, OneToOneField)])
-
+        # The concrete_models is a set of all multi-table models this model
+        # represents, that is new_class if it is a concrete model, plus all
+        # multi-table inherited parents. Needed for fast __eq__ implementation.
+        new_class._meta.concrete_models = set()
+        if not is_proxy and not abstract:
+            new_class._meta.concrete_models.add(new_class)
         for base in parents:
             original_base = base
             if not hasattr(base, '_meta'):
@@ -152,6 +157,8 @@ class ModelBase(type):
                 while base._meta.proxy:
                     # Skip over a proxy class to the "real" base it proxies.
                     base = base._meta.proxy_for_model
+                # Found a concrete model, and this class represents it.
+                new_class._meta.concrete_models.update(base._meta.concrete_models)
                 if base in o2o_map:
                     field = o2o_map[base]
                 elif not is_proxy:
@@ -382,7 +389,14 @@ class Model(object):
         return '%s object' % self.__class__.__name__
 
     def __eq__(self, other):
-        return isinstance(other, self.__class__) and self._get_pk_val() == other._get_pk_val()
+        """
+        Two models are considered equal if they share a common multitable-inherited parent
+        or if one is an instance of the other. This can be used by checking the _meta
+        .concrete_models variable.
+        """
+        return bool(isinstance(other, Model) and
+               self._meta.concrete_models.intersection(other._meta.concrete_models) and 
+               self._get_pk_val() == other._get_pk_val())
 
     def __ne__(self, other):
         return not self.__eq__(other)
diff --git a/tests/modeltests/basic/tests.py b/tests/modeltests/basic/tests.py
index ff09d9b..c066f43 100644
--- a/tests/modeltests/basic/tests.py
+++ b/tests/modeltests/basic/tests.py
@@ -206,6 +206,9 @@ class ModelTest(TestCase):
         # Check that != and == operators behave as expecte on instances
         self.assertTrue(a7 != a8)
         self.assertFalse(a7 == a8)
+        # And that they work when the other is not a Model instance
+        self.assertFalse(a7 == None)
+        self.assertFalse(a7 == self)
         self.assertEqual(a8, Article.objects.get(id__exact=a8.id))
 
         self.assertTrue(Article.objects.get(id__exact=a8.id) != Article.objects.get(id__exact=a7.id))
diff --git a/tests/modeltests/defer/tests.py b/tests/modeltests/defer/tests.py
index 5f6c53d..9cf32ee 100644
--- a/tests/modeltests/defer/tests.py
+++ b/tests/modeltests/defer/tests.py
@@ -23,10 +23,18 @@ class DeferTests(TestCase):
         p1 = Primary.objects.create(name="p1", value="xx", related=s1)
 
         qs = Primary.objects.all()
-
         self.assert_delayed(qs.defer("name")[0], 1)
         self.assert_delayed(qs.only("name")[0], 2)
         self.assert_delayed(qs.defer("related__first")[0], 0)
+        
+        # deferred instances are equal to their non-deferred counterpart
+        deferred_p1 = qs.defer("name")[0]
+        self.assertTrue(deferred_p1==p1)
+        # The __eq__ operator is symmetric as well as the == operator
+        self.assertTrue(p1==deferred_p1)
+        self.assertTrue(deferred_p1.__eq__(p1))
+        self.assertTrue(p1.__eq__(deferred_p1))
+
 
         obj = qs.select_related().only("related__first")[0]
         self.assert_delayed(obj, 2)
diff --git a/tests/modeltests/model_inheritance/tests.py b/tests/modeltests/model_inheritance/tests.py
index 334297a..28b9258 100644
--- a/tests/modeltests/model_inheritance/tests.py
+++ b/tests/modeltests/model_inheritance/tests.py
@@ -69,6 +69,20 @@ class ModelInheritanceTests(TestCase):
             StudentWorker.objects.get, pk__lt=sw2.pk + 100
         )
 
+        # A multi-table inherited instance is considered equal to its base
+        # class
+        w = Worker(pk=1)
+        sw = StudentWorker(pk=1)
+        self.assertTrue(w==sw)
+        # The __eq__ operator is symmetric as well as the '==' operator
+        self.assertTrue(sw==w)
+        self.assertTrue(w.__eq__(sw))
+        self.assertTrue(sw.__eq__(w))
+        # A common abstract base class does not lead to equality
+        s = Student(pk=1)
+        self.assertFalse(s==w)
+        
+
     def test_multiple_table(self):
         post = Post.objects.create(title="Lorem Ipsum")
         # The Post model has distinct accessors for the Comment and Link models.
@@ -269,6 +283,13 @@ class ModelInheritanceTests(TestCase):
         self.assertNumQueries(1,
             lambda: ItalianRestaurant.objects.select_related("chef")[0].chef
         )
+        # Having a common parent works when there are models in the chain
+        r = Place(pk=1)
+        i = ItalianRestaurant(pk=1)
+        self.assertTrue(r==i)
+        # A common concrete (multitable-inherited) parent leads to equality
+        s = Supplier(pk=1)
+        self.assertTrue(i==s)
 
     def test_mixin_init(self):
         m = MixinModel()
diff --git a/tests/modeltests/proxy_models/tests.py b/tests/modeltests/proxy_models/tests.py
index 0a46a25..a4c7d40 100644
--- a/tests/modeltests/proxy_models/tests.py
+++ b/tests/modeltests/proxy_models/tests.py
@@ -45,6 +45,18 @@ class ProxyModelTests(TestCase):
         self.assertEqual(MyPerson.objects.get(name="Foo McBar").id, person.id)
         self.assertFalse(MyPerson.objects.get(id=person.id).has_special_name())
 
+    def test_proxy_eq(self):
+        """
+        Proxied models are considered equal to their concrete base class.
+        """
+        p = Person(pk=1)
+        mp = MyPerson(pk=1)
+        self.assertTrue(p==mp)
+        # the __eq__ operator is symmetric as well as the == operator
+        self.assertTrue(mp==p)
+        self.assertTrue(p.__eq__(mp))
+        self.assertTrue(mp.__eq__(p))
+
     def test_no_proxy(self):
         """
         Person is not proxied by StatusPerson subclass.
