diff --git a/django/contrib/auth/__init__.py b/django/contrib/auth/__init__.py
index d5d4430dc0..065eaddd59 100644
--- a/django/contrib/auth/__init__.py
+++ b/django/contrib/auth/__init__.py
@@ -97,7 +97,10 @@ def get_user_model():
     from django.conf import settings
     from django.db.models import get_model
 
-    app_label, model_name = settings.AUTH_USER_MODEL.split('.')
+    try:
+        app_label, model_name = settings.AUTH_USER_MODEL.split('.')
+    except ValueError:
+        raise ImproperlyConfigured("AUTH_USER_MODEL must be of the form 'app_label.model_name'")
     return get_model(app_label, model_name)
 
 
diff --git a/django/core/management/validation.py b/django/core/management/validation.py
index 462d1ec0b6..fa3edb4430 100644
--- a/django/core/management/validation.py
+++ b/django/core/management/validation.py
@@ -285,6 +285,16 @@ def get_validation_errors(outfile, app=None):
                     if r.get_accessor_name() == rel_query_name:
                         e.add(opts, "Reverse query name for m2m field '%s' clashes with related field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.get_accessor_name(), f.name))
 
+        # Check swappable attribute.
+        if opts.swapped:
+            try:
+                app_label, model_name = opts.swapped.split('.')
+            except ValueError:
+                e.add(opts, "%s is not of the form 'app_label.app_name'." % opts.swappable)
+                continue
+            if not models.get_model(app_label, model_name):
+                e.add(opts, "Model has been swapped out for '%s' which has not been installed or is abstract." % opts.swapped)
+
         # Check ordering attribute.
         if opts.ordering:
             for field_name in opts.ordering:
diff --git a/tests/modeltests/invalid_models/invalid_models/models.py b/tests/modeltests/invalid_models/invalid_models/models.py
index 6b2d6bd603..3f95d314e3 100644
--- a/tests/modeltests/invalid_models/invalid_models/models.py
+++ b/tests/modeltests/invalid_models/invalid_models/models.py
@@ -310,6 +310,26 @@ class SwappedModel(models.Model):
         swappable = 'TEST_SWAPPED_MODEL'
 
 
+class BadSwappableValue(models.Model):
+    """A model that can be swapped out; during testing, the swappable
+    value is not of the format app.model
+    """
+    name = models.CharField(max_length=100)
+
+    class Meta:
+        swappable = 'TEST_SWAPPED_MODEL_BAD_VALUE'
+
+
+class BadSwappableModel(models.Model):
+    """A model that can be swapped out; during testing, the swappable
+    value references an unknown model.
+    """
+    name = models.CharField(max_length=100)
+
+    class Meta:
+        swappable = 'TEST_SWAPPED_MODEL_BAD_MODEL'
+
+
 class HardReferenceModel(models.Model):
     fk_1 = models.ForeignKey(SwappableModel, related_name='fk_hardref1')
     fk_2 = models.ForeignKey('invalid_models.SwappableModel', related_name='fk_hardref2')
@@ -433,6 +453,8 @@ invalid_models.hardreferencemodel: 'fk_3' defines a relation with the model 'inv
 invalid_models.hardreferencemodel: 'fk_4' defines a relation with the model 'invalid_models.SwappedModel', which has been swapped out. Update the relation to point at settings.TEST_SWAPPED_MODEL.
 invalid_models.hardreferencemodel: 'm2m_3' defines a relation with the model 'invalid_models.SwappedModel', which has been swapped out. Update the relation to point at settings.TEST_SWAPPED_MODEL.
 invalid_models.hardreferencemodel: 'm2m_4' defines a relation with the model 'invalid_models.SwappedModel', which has been swapped out. Update the relation to point at settings.TEST_SWAPPED_MODEL.
+invalid_models.badswappablevalue: TEST_SWAPPED_MODEL_BAD_VALUE is not of the form 'app_label.app_name'.
+invalid_models.badswappablemodel: Model has been swapped out for 'not_an_app.Target' which has not been installed or is abstract.
 """
 
 if not connection.features.interprets_empty_strings_as_nulls:
diff --git a/tests/modeltests/invalid_models/tests.py b/tests/modeltests/invalid_models/tests.py
index 787c0e5c92..6050a20880 100644
--- a/tests/modeltests/invalid_models/tests.py
+++ b/tests/modeltests/invalid_models/tests.py
@@ -36,7 +36,11 @@ class InvalidModelTestCase(unittest.TestCase):
     # set to *something* in order for the test to work. However, it's
     # easier to set this up as an override than to require every developer
     # to specify a value in their test settings.
-    @override_settings(TEST_SWAPPED_MODEL='invalid_models.Target')
+    @override_settings(
+        TEST_SWAPPED_MODEL='invalid_models.Target',
+        TEST_SWAPPED_MODEL_BAD_VALUE='not-a-model',
+        TEST_SWAPPED_MODEL_BAD_MODEL='not_an_app.Target',
+    )
     def test_invalid_models(self):
         try:
             module = load_app("modeltests.invalid_models.invalid_models")