diff --git a/django/db/models/base.py b/django/db/models/base.py
index 7bb3fa4706..0955a5a579 100644
--- a/django/db/models/base.py
+++ b/django/db/models/base.py
@@ -1926,6 +1926,12 @@ class Model(metaclass=ModelBase):
                         id='models.W038',
                     )
                 )
+            fields = (
+                field
+                for constraint in cls._meta.constraints if isinstance(constraint, UniqueConstraint)
+                for field in constraint.fields
+            )
+            errors.extend(cls._check_local_fields(fields, 'constraints'))
         return errors
 
 
diff --git a/docs/ref/checks.txt b/docs/ref/checks.txt
index 1259a4a285..09bb799ebe 100644
--- a/docs/ref/checks.txt
+++ b/docs/ref/checks.txt
@@ -308,17 +308,17 @@ Models
 * **models.E009**: All ``index_together`` elements must be lists or tuples.
 * **models.E010**: ``unique_together`` must be a list or tuple.
 * **models.E011**: All ``unique_together`` elements must be lists or tuples.
-* **models.E012**: ``indexes/index_together/unique_together`` refers to the
-  nonexistent field ``<field name>``.
-* **models.E013**: ``indexes/index_together/unique_together`` refers to a
-  ``ManyToManyField`` ``<field name>``, but ``ManyToManyField``\s are not
-  supported for that option.
+* **models.E012**: ``constraints/indexes/index_together/unique_together``
+  refers to the nonexistent field ``<field name>``.
+* **models.E013**: ``constraints/indexes/index_together/unique_together``
+  refers to a ``ManyToManyField`` ``<field name>``, but ``ManyToManyField``\s
+  are not supported for that option.
 * **models.E014**: ``ordering`` must be a tuple or list (even if you want to
   order by only one field).
 * **models.E015**: ``ordering`` refers to the nonexistent field, related field,
   or lookup ``<field name>``.
-* **models.E016**: ``indexes/index_together/unique_together`` refers to field
-  ``<field_name>`` which is not local to model ``<model>``.
+* **models.E016**: ``constraints/indexes/index_together/unique_together``
+  refers to field ``<field_name>`` which is not local to model ``<model>``.
 * **models.E017**: Proxy model ``<model>`` contains model fields.
 * **models.E018**: Autogenerated column name too long for field ``<field>``.
   Maximum length is ``<maximum length>`` for database ``<alias>``.
diff --git a/tests/invalid_models_tests/test_models.py b/tests/invalid_models_tests/test_models.py
index 6c062b2990..7847ee8486 100644
--- a/tests/invalid_models_tests/test_models.py
+++ b/tests/invalid_models_tests/test_models.py
@@ -1501,3 +1501,70 @@ class ConstraintsTests(TestCase):
                 ]
 
         self.assertEqual(Model.check(databases=self.databases), [])
+
+    def test_unique_constraint_pointing_to_missing_field(self):
+        class Model(models.Model):
+            class Meta:
+                constraints = [models.UniqueConstraint(fields=['missing_field'], name='name')]
+
+        self.assertEqual(Model.check(databases=self.databases), [
+            Error(
+                "'constraints' refers to the nonexistent field "
+                "'missing_field'.",
+                obj=Model,
+                id='models.E012',
+            ),
+        ])
+
+    def test_unique_constraint_pointing_to_m2m_field(self):
+        class Model(models.Model):
+            m2m = models.ManyToManyField('self')
+
+            class Meta:
+                constraints = [models.UniqueConstraint(fields=['m2m'], name='name')]
+
+        self.assertEqual(Model.check(databases=self.databases), [
+            Error(
+                "'constraints' refers to a ManyToManyField 'm2m', but "
+                "ManyToManyFields are not permitted in 'constraints'.",
+                obj=Model,
+                id='models.E013',
+            ),
+        ])
+
+    def test_unique_constraint_pointing_to_non_local_field(self):
+        class Parent(models.Model):
+            field1 = models.IntegerField()
+
+        class Child(Parent):
+            field2 = models.IntegerField()
+
+            class Meta:
+                constraints = [
+                    models.UniqueConstraint(fields=['field2', 'field1'], name='name'),
+                ]
+
+        self.assertEqual(Child.check(databases=self.databases), [
+            Error(
+                "'constraints' refers to field 'field1' which is not local to "
+                "model 'Child'.",
+                hint='This issue may be caused by multi-table inheritance.',
+                obj=Child,
+                id='models.E016',
+            ),
+        ])
+
+    def test_unique_constraint_pointing_to_fk(self):
+        class Target(models.Model):
+            pass
+
+        class Model(models.Model):
+            fk_1 = models.ForeignKey(Target, models.CASCADE, related_name='target_1')
+            fk_2 = models.ForeignKey(Target, models.CASCADE, related_name='target_2')
+
+            class Meta:
+                constraints = [
+                    models.UniqueConstraint(fields=['fk_1_id', 'fk_2'], name='name'),
+                ]
+
+        self.assertEqual(Model.check(databases=self.databases), [])