diff --git a/django/db/models/fields/__init__.py b/django/db/models/fields/__init__.py
index 9037265..5e1d51f 100644
--- a/django/db/models/fields/__init__.py
+++ b/django/db/models/fields/__init__.py
@@ -115,6 +115,8 @@ class Field(object):
             messages.update(getattr(c, 'default_error_messages', {}))
         messages.update(error_messages or {})
         self.error_messages = messages
+        self._declared_on_class = None
+        self._first_concrete_class = None
 
     def __cmp__(self, other):
         # This is needed because bisect does not take a comparison function.
@@ -231,10 +233,33 @@ class Field(object):
     def contribute_to_class(self, cls, name):
         self.set_attributes_from_name(name)
         self.model = cls
+        if self._declared_on_class is None:
+            self._declared_on_class = cls
+        if self._first_concrete_class is None and not cls._meta.abstract:
+            self._first_concrete_class = cls
+        for f in cls._meta.local_fields + cls._meta.local_many_to_many:
+            if f.name == self.name:
+                if self._is_duplicate(f):
+                    return
+                break
         cls._meta.add_field(self)
         if self.choices:
             setattr(cls, 'get_%s_display' % self.name, curry(cls._get_FIELD_display, field=self))
 
+    def _is_duplicate(self, other):
+        """
+        Returns ``True`` if ``self`` is a duplicate of ``other`` and false otherwise.
+        
+        Two fields are duplicates if they were declared on the same class
+        and if either neither field has been on a concrete class or one
+        field's first concrete class is a subclass of the other field's first
+        concrete class.
+        
+        """
+        ocon = other._first_concrete_class
+        scon = self._first_concrete_class
+        return other._declared_on_class == self._declared_on_class and ((ocon is None and scon is None) or issubclass(scon, ocon) or issubclass(ocon, scon))
+
     def get_attname(self):
         return self.name
 
diff --git a/django/db/models/options.py b/django/db/models/options.py
index 6f0f406..55072e6 100644
--- a/django/db/models/options.py
+++ b/django/db/models/options.py
@@ -233,13 +233,15 @@ class Options(object):
 
     def _fill_fields_cache(self):
         cache = []
+        checks = {}
         for parent in self.parents:
             for field, model in parent._meta.get_fields_with_model():
                 if model:
                     cache.append((field, model))
                 else:
                     cache.append((field, parent))
-        cache.extend([(f, None) for f in self.local_fields])
+                checks[field.name] = field
+        cache.extend([(f, None) for f in self.local_fields if f.name not in checks or not f._is_duplicate(checks[f.name])])
         self._field_cache = tuple(cache)
         self._field_name_cache = [x for x, _ in cache]
 
@@ -263,14 +265,17 @@ class Options(object):
 
     def _fill_m2m_cache(self):
         cache = SortedDict()
+        checks = {}
         for parent in self.parents:
             for field, model in parent._meta.get_m2m_with_model():
                 if model:
                     cache[field] = model
                 else:
                     cache[field] = parent
+                checks[field.name] = field
         for field in self.local_many_to_many:
-            cache[field] = None
+            if field.name not in checks or not field._is_duplicate(checks[field.name]):
+                cache[field] = None
         self._m2m_cache = cache
 
     def get_field(self, name, many_to_many=True):
diff --git a/tests/modeltests/model_inheritance/models.py b/tests/modeltests/model_inheritance/models.py
index a0fed8a..46cf8f6 100644
--- a/tests/modeltests/model_inheritance/models.py
+++ b/tests/modeltests/model_inheritance/models.py
@@ -48,9 +48,13 @@ class StudentWorker(Student, Worker):
 class Post(models.Model):
     title = models.CharField(max_length=50)
 
+class Tag(models.Model):
+    name = models.CharField(max_length=10)
+
 class Attachment(models.Model):
     post = models.ForeignKey(Post, related_name='attached_%(class)s_set')
     content = models.TextField()
+    tags = models.ManyToManyField(Tag, related_name='tagged_%(class)s_set')
 
     class Meta:
         abstract = True
@@ -64,6 +68,18 @@ class Comment(Attachment):
 class Link(Attachment):
     url = models.URLField()
 
+class OrangeAttachment(Attachment):
+    class Meta:
+        abstract = True
+
+class BananaAttachment(Attachment):
+    class Meta:
+        abstract = True
+
+class BlueberryAttachment(Attachment):
+    class Meta:
+        abstract = True
+
 #
 # Multi-table inheritance
 #
diff --git a/tests/modeltests/model_inheritance/tests.py b/tests/modeltests/model_inheritance/tests.py
index 334297a..5e61784 100644
--- a/tests/modeltests/model_inheritance/tests.py
+++ b/tests/modeltests/model_inheritance/tests.py
@@ -4,7 +4,8 @@ from django.core.exceptions import FieldError
 from django.test import TestCase
 
 from models import (Chef, CommonInfo, ItalianRestaurant, ParkingLot, Place,
-    Post, Restaurant, Student, StudentWorker, Supplier, Worker, MixinModel)
+    Post, Restaurant, Student, StudentWorker, Supplier, Worker, MixinModel,
+    OrangeAttachment, BananaAttachment, BlueberryAttachment)
 
 
 class ModelInheritanceTests(TestCase):
@@ -69,6 +70,41 @@ class ModelInheritanceTests(TestCase):
             StudentWorker.objects.get, pk__lt=sw2.pk + 100
         )
 
+    def test_multiple_abstract_inheritance(self):
+        # Define class here to avoid model validation errors while running tests.
+        def check_duplicates(cls):
+            field_names = [field.name for field in cls._meta.fields]
+            field_name_set = list(set(field_names))
+            self.assertEqual(sorted(field_names), sorted(field_name_set))
+            m2m_names = [field.name for field in cls._meta.many_to_many]
+            m2m_name_set = list(set(m2m_names))
+            self.assertEqual(sorted(m2m_names), sorted(m2m_name_set))
+
+        class SmoothieAttachment(OrangeAttachment, BananaAttachment):
+            class Meta:
+                app_label = 'model_inheritance'
+
+        check_duplicates(SmoothieAttachment)
+
+        class AbstractSmoothieAttachment(OrangeAttachment, BananaAttachment):
+            class Meta:
+                abstract = True
+                app_label = 'model_inheritance'
+
+        check_duplicates(AbstractSmoothieAttachment)
+
+        class BlueberrySmoothieAttachment(BlueberryAttachment, SmoothieAttachment):
+            class Meta:
+                app_label = 'model_inheritance'
+
+        check_duplicates(BlueberrySmoothieAttachment)
+
+        class SmoothieBlueberryAttachment(SmoothieAttachment, BlueberryAttachment):
+            class Meta:
+                app_label = 'model_inheritance'
+
+        check_duplicates(SmoothieBlueberryAttachment)
+
     def test_multiple_table(self):
         post = Post.objects.create(title="Lorem Ipsum")
         # The Post model has distinct accessors for the Comment and Link models.
