diff --git a/django/contrib/admin/options.py b/django/contrib/admin/options.py
index 7373837..487fc4e 100644
--- a/django/contrib/admin/options.py
+++ b/django/contrib/admin/options.py
@@ -13,7 +13,7 @@ from django.contrib.admin.util import (unquote, flatten_fieldsets, get_deleted_o
 from django.contrib.admin.templatetags.admin_static import static
 from django.contrib import messages
 from django.views.decorators.csrf import csrf_protect
-from django.core.exceptions import PermissionDenied, ValidationError, FieldError
+from django.core.exceptions import PermissionDenied, ValidationError, FieldError, ImproperlyConfigured
 from django.core.paginator import Paginator
 from django.core.urlresolvers import reverse
 from django.db import models, transaction, router
@@ -1467,6 +1467,17 @@ class InlineModelAdmin(BaseModelAdmin):
             js.extend(['SelectBox.js', 'SelectFilter2.js'])
         return forms.Media(js=[static('admin/js/%s' % url) for url in js])
 
+    def get_extra(self, request, obj=None, **kwargs):
+        """Get the number of extra inline forms needed"""
+        if not isinstance(self.extra, int):
+            raise ImproperlyConfigured("'%s.extra' should be a integer."
+                                       % self.__class__.__name__)
+        return self.extra
+
+    def get_max_num(self, request, obj=None, **kwargs):
+        """Get the max number of extra inline forms needed"""
+        return self.max_num
+
     def get_formset(self, request, obj=None, **kwargs):
         """Returns a BaseInlineFormSet class for use in admin add/change views."""
         if self.declared_fieldsets:
@@ -1493,8 +1504,8 @@ class InlineModelAdmin(BaseModelAdmin):
             "fields": fields,
             "exclude": exclude,
             "formfield_callback": partial(self.formfield_for_dbfield, request=request),
-            "extra": self.extra,
-            "max_num": self.max_num,
+            "extra": self.get_extra(request, obj, *kwargs),
+            "max_num": self.get_max_num(request, obj, *kwargs),
             "can_delete": can_delete,
         }
 
diff --git a/django/contrib/admin/validation.py b/django/contrib/admin/validation.py
index 8d65f96..06b5055 100644
--- a/django/contrib/admin/validation.py
+++ b/django/contrib/admin/validation.py
@@ -199,11 +199,6 @@ def validate_inline(cls, parent, parent_model):
 
     fk = _get_foreign_key(parent_model, cls.model, fk_name=cls.fk_name, can_fail=True)
 
-    # extra = 3
-    if not isinstance(cls.extra, int):
-        raise ImproperlyConfigured("'%s.extra' should be a integer."
-                % cls.__name__)
-
     # max_num = None
     max_num = getattr(cls, 'max_num', None)
     if max_num is not None and not isinstance(max_num, int):
diff --git a/tests/admin_inlines/admin.py b/tests/admin_inlines/admin.py
index 44671d0..2f88248 100644
--- a/tests/admin_inlines/admin.py
+++ b/tests/admin_inlines/admin.py
@@ -129,6 +129,22 @@ class ChildModel1Inline(admin.TabularInline):
 class ChildModel2Inline(admin.StackedInline):
     model = ChildModel2
 
+# admin for #19425 and #18388
+class BinaryTreeAdmin(admin.TabularInline):
+    model = BinaryTree
+
+    def get_extra(self, request, obj=None, **kwargs):
+        extra = 2
+        if obj:
+            return extra - obj.binarytree_set.count()
+        return extra
+
+    def get_max_num(self, request, obj=None, **kwargs):
+        max_num = 3
+        if obj:
+            return max_num - obj.binarytree_set.count()
+        return max_num
+
 # admin for #19524
 class SightingInline(admin.TabularInline):
     model = Sighting
@@ -150,4 +166,5 @@ site.register(Author, AuthorAdmin)
 site.register(CapoFamiglia, inlines=[ConsigliereInline, SottoCapoInline, ReadOnlyInlineInline])
 site.register(ProfileCollection, inlines=[ProfileInline])
 site.register(ParentModelWithCustomPk, inlines=[ChildModel1Inline, ChildModel2Inline])
+site.register(BinaryTree, inlines=[BinaryTreeAdmin])
 site.register(ExtraTerrestrial, inlines=[SightingInline])
diff --git a/tests/admin_inlines/models.py b/tests/admin_inlines/models.py
index 82c1c3f..d4ba0ab 100644
--- a/tests/admin_inlines/models.py
+++ b/tests/admin_inlines/models.py
@@ -183,6 +183,12 @@ class ChildModel2(models.Model):
     def get_absolute_url(self):
         return '/child_model2/'
 
+
+# Models for #19425
+class BinaryTree(models.Model):
+    name = models.CharField(max_length=100)
+    parent = models.ForeignKey('self', null=True, blank=True)
+
 # Models for #19524
 
 class LifeForm(models.Model):
