diff --git a/AUTHORS b/AUTHORS
index 6c90cd0..41367e7 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -369,6 +369,7 @@ answer newbie questions, and generally made Django that much better:
     Neal Norwitz <nnorwitz@google.com>
     Todd O'Bryan <toddobryan@mac.com>
     Selwin Ong <selwin@ui.co.id>
+    Paul Oswald <pauloswald@gmail.com>
     Christian Oudard <christian.oudard@gmail.com>
     oggie rob <oz.robharvey@gmail.com>
     oggy <ognjen.maric@gmail.com>
diff --git a/tests/regressiontests/admin_inlines/models.py b/tests/regressiontests/admin_inlines/models.py
index bb299f3..c9fcc04 100644
--- a/tests/regressiontests/admin_inlines/models.py
+++ b/tests/regressiontests/admin_inlines/models.py
@@ -66,6 +66,24 @@ class Holder2(models.Model):
     dummy = models.IntegerField()
 
 
+# Objects for bug #14642 Test
+class Thing(models.Model):
+    description = models.CharField(max_length=256)
+
+class ThingItem(models.Model):
+    description = models.CharField(max_length=256)
+    thing = models.ForeignKey(Thing)
+
+class ThingItemInline(admin.TabularInline):
+    model = ThingItem
+    extra = 0
+
+class ThingAdmin(admin.ModelAdmin):
+    inlines = [ThingItemInline,]
+
+admin.site.register(Thing, ThingAdmin)
+
+
 class Inner2(models.Model):
     dummy = models.IntegerField()
     holder = models.ForeignKey(Holder2)
diff --git a/tests/regressiontests/admin_inlines/tests.py b/tests/regressiontests/admin_inlines/tests.py
index 915c6fa..e0c17b0 100644
--- a/tests/regressiontests/admin_inlines/tests.py
+++ b/tests/regressiontests/admin_inlines/tests.py
@@ -1,11 +1,11 @@
 from django.contrib.admin.helpers import InlineAdminForm
 from django.contrib.contenttypes.models import ContentType
 from django.test import TestCase
+from django.core.urlresolvers import reverse
 
 # local test models
 from models import (Holder, Inner, InnerInline, Holder2, Inner2, Holder3,
-    Inner3, Person, OutfitItem, Fashionista, Teacher, Parent, Child)
-
+    Inner3, Person, OutfitItem, Fashionista, Teacher, Parent, Child, Thing, ThingItem)
 
 class TestInline(TestCase):
     fixtures = ['admin-views-users.xml']
@@ -136,3 +136,81 @@ class TestInlineAdminForm(TestCase):
         iaf = InlineAdminForm(None, None, {}, {}, joe)
         parent_ct = ContentType.objects.get_for_model(Parent)
         self.assertEqual(iaf.original.content_type, parent_ct)
+
+class TestEditingInlineViews(TestCase):
+    fixtures = ['admin-views-users.xml']
+
+    def setUp(self):
+        result = self.client.login(username='super', password='secret')
+        self.failUnlessEqual(result, True)
+        # Set up a thing to be modified in the test
+        self.thing = Thing.objects.create(description="Parent object")
+        self.thing_item_1 = ThingItem.objects.create(description="Item #1", thing=self.thing)
+        self.thing_item_2 = ThingItem.objects.create(description="Item #2", thing=self.thing)
+
+    def tearDown(self):
+        self.client.logout()
+        self.thing_item_1.delete()
+        self.thing_item_2.delete()
+        self.thing.delete()
+
+    def test_concurrent_editing_views(self):
+        """
+        A ``POST`` to the edit view by two clients simultaneously is properly handled
+
+        We are going to simulate two test clients by submitting slightly different data twice.
+        This would be equivalent to working with two tabs open in a browser. Individually each of
+        these forms is valid but the second one is invalid when submitted one after the other. The
+        server needs to handle this case.
+        """
+
+        data = [
+            # An existing item has been deleted.
+            {
+                u'description': [u'A new description'],
+                u'thingitem_set-MAX_NUM_FORMS': [u'0'],
+                u'thingitem_set-TOTAL_FORMS': [u'2'],
+                u'thingitem_set-INITIAL_FORMS': [u'2'],
+                u'thingitem_set-0-DELETE': [u''],
+                u'thingitem_set-0-id': [u'%s' % (self.thing_item_1.pk,)],
+                u'thingitem_set-0-thing': [u'%s' % (self.thing.pk,)],
+                u'thingitem_set-0-description': [u'New item #1 description'],
+                u'thingitem_set-1-DELETE': [u'on'],
+                u'thingitem_set-1-id': [u'%s' % (self.thing_item_2.pk,)],
+                u'thingitem_set-1-thing': [u'%s' % (self.thing.pk,)],
+                u'thingitem_set-1-description': [u'Deleted item #2 description'],
+            },
+
+            # In this second form, we are now attempting to edit the deleted item. This form is
+            # invalid but the user submitting it doesn't know that yet.
+            {
+                u'description': [u'A new description #2'],
+                u'thingitem_set-MAX_NUM_FORMS': [u'0'],
+                u'thingitem_set-TOTAL_FORMS': [u'2'],
+                u'thingitem_set-INITIAL_FORMS': [u'2'],
+                u'thingitem_set-0-DELETE': [u''],
+                u'thingitem_set-0-id': [u'%s' % (self.thing_item_1.pk,)],
+                u'thingitem_set-0-thing': [u'%s' % (self.thing.pk,)],
+                u'thingitem_set-0-description': [u'New item #1 description'],
+                u'thingitem_set-1-DELETE': [u''],
+                u'thingitem_set-1-id': [u'%s' % (self.thing_item_2.pk,)],
+                u'thingitem_set-1-thing': [u'%s' % (self.thing.pk,)],
+                u'thingitem_set-1-description': [u'Deleted item #2 description'],
+            },
+        ]
+        edit_url = 'admin:%s_%s_change' %(self.thing._meta.app_label,  self.thing._meta.module_name)
+        view_url = 'admin:%s_%s_changelist' %(self.thing._meta.app_label,  self.thing._meta.module_name)
+
+        count = Thing.objects.count()
+        response = self.client.post(reverse(edit_url, args=[self.thing.pk]), data[0])
+
+        # Check our first edit was accepted
+        self.assertRedirects(response, reverse(view_url), 302, 200)
+
+        # Submit the second form. (this might be a second tab in the browser, or a second user)
+        response = self.client.post(reverse(edit_url, args=[self.thing.pk]), data[1])
+
+        # Check our second edit was handled
+        self.assertRedirects(response, reverse(view_url), 302, 200)
+
+
