diff --git a/django/contrib/admin/templates/admin/edit_inline/tabular.html b/django/contrib/admin/templates/admin/edit_inline/tabular.html
index a5b1a89..7f6c34a 100644
--- a/django/contrib/admin/templates/admin/edit_inline/tabular.html
+++ b/django/contrib/admin/templates/admin/edit_inline/tabular.html
@@ -1,4 +1,4 @@
-{% load i18n adminmedia %}
+{% load i18n adminmedia admin_modify %}
 <div class="inline-group" id="{{ inline_admin_formset.formset.prefix }}-group">
   <div class="tabular inline-related {% if forloop.last %}last-related{% endif %}">
 {{ inline_admin_formset.formset.management_form }}
@@ -18,7 +18,7 @@
      <tbody>
      {% for inline_admin_form in inline_admin_formset %}
         {% if inline_admin_form.form.non_field_errors %}
-        <tr><td colspan="{{ inline_admin_form.field_count }}">{{ inline_admin_form.form.non_field_errors }}</td></tr>
+        <tr><td colspan="{{ inline_admin_form|cell_count }}">{{ inline_admin_form.form.non_field_errors }}</td></tr>
         {% endif %}
         <tr class="{% cycle "row1" "row2" %} {% if inline_admin_form.original or inline_admin_form.show_url %}has_original{% endif %}{% if forloop.last %} empty-form{% endif %}"
              id="{{ inline_admin_formset.formset.prefix }}-{% if not forloop.last %}{{ forloop.counter0 }}{% else %}empty{% endif %}">
diff --git a/django/contrib/admin/templatetags/admin_modify.py b/django/contrib/admin/templatetags/admin_modify.py
index fe88043..5c00de3 100644
--- a/django/contrib/admin/templatetags/admin_modify.py
+++ b/django/contrib/admin/templatetags/admin_modify.py
@@ -40,3 +40,17 @@ def submit_row(context):
         'show_save': True
     }
 submit_row = register.inclusion_tag('admin/submit_line.html', takes_context=True)(submit_row)
+
+def cell_count(inline_admin_form):
+    """ Returns the number of cells used in a tabular inline """
+    count = 1 # Hidden cell with hidden 'id' field
+    for fieldset in inline_admin_form:
+        # Loop through all the fields (one per cell)
+        for line in fieldset:
+            for field in line:
+                count += 1
+    if inline_admin_form.formset.can_delete:
+        # Delete checkbox
+        count += 1
+    return count
+cell_count = register.filter(cell_count)
diff --git a/tests/regressiontests/admin_inlines/models.py b/tests/regressiontests/admin_inlines/models.py
index 4e5c4e3..772152a 100644
--- a/tests/regressiontests/admin_inlines/models.py
+++ b/tests/regressiontests/admin_inlines/models.py
@@ -6,6 +6,7 @@ from django.db import models
 from django.contrib import admin
 from django.contrib.contenttypes.models import ContentType
 from django.contrib.contenttypes import generic
+from django import forms
 
 class Parent(models.Model):
     name = models.CharField(max_length=50)
@@ -123,3 +124,31 @@ class InlineWeakness(admin.TabularInline):
     extra = 1
 
 admin.site.register(Fashionista, inlines=[InlineWeakness])
+
+
+# Models for #13510 --------------------
+
+class TitleCollection(models.Model):
+    pass
+    
+class Title(models.Model):
+    collection = models.ForeignKey(TitleCollection, blank=True, null=True)
+    title1 = models.CharField(max_length=100)
+    title2 = models.CharField(max_length=100)
+    
+class TitleForm(forms.ModelForm):
+    
+    def clean(self):
+        cleaned_data = self.cleaned_data
+        title1 = cleaned_data.get("title1")
+        title2 = cleaned_data.get("title2")
+        if title1 != title2:
+            raise forms.ValidationError("The two titles must be the same")
+        return cleaned_data
+
+class TitleInline(admin.TabularInline):
+    model = Title
+    form = TitleForm
+    extra = 1
+
+admin.site.register(TitleCollection, inlines=[TitleInline])
diff --git a/tests/regressiontests/admin_inlines/tests.py b/tests/regressiontests/admin_inlines/tests.py
index b10474d..69ff96c 100644
--- a/tests/regressiontests/admin_inlines/tests.py
+++ b/tests/regressiontests/admin_inlines/tests.py
@@ -67,6 +67,23 @@ class TestInline(TestCase):
         self.assertEqual(response.status_code, 302)
         self.assertEqual(len(Fashionista.objects.filter(person__firstname='Imelda')), 1)
 
+    def test_tabular_non_field_errors(self):
+        """ Ensure that non_field_errors are displayed correctly, including
+            the right value for colspan. 
+            Refs #13510.
+        """
+        data = {
+            'title_set-TOTAL_FORMS': 1,
+            'title_set-INITIAL_FORMS': 0,
+            'title_set-MAX_NUM_FORMS': 0,
+            '_save': u'Save',
+            'title_set-0-title1': 'a title',
+            'title_set-0-title2': 'a different title',
+        }
+        response = self.client.post('/test_admin/admin/admin_inlines/titlecollection/add/', data)
+        # Here colspan is "4": two fields (title1 and title2), one hidden field and the delete checkbock.
+        self.assertContains(response, '<tr><td colspan="4"><ul class="errorlist"><li>The two titles must be the same</li></ul></td></tr>')
+        
 class TestInlineMedia(TestCase):
     fixtures = ['admin-views-users.xml']
 
