diff --git a/core/lib/Drupal/Core/Field/FieldConfigInterface.php b/core/lib/Drupal/Core/Field/FieldConfigInterface.php
index 11da0df..f5a86a6 100644
--- a/core/lib/Drupal/Core/Field/FieldConfigInterface.php
+++ b/core/lib/Drupal/Core/Field/FieldConfigInterface.php
@@ -178,7 +178,7 @@ public function addPropertyConstraints($name, array $constraints);
    * @code
    *   // Add a constraint to the 'field_username' FieldItemList.
    *   // e.g. $node->field_username
-   *   $fields['field_username']->addConstraint('UserNameUnique', []);
+   *   $fields['field_username']->addConstraint('UniqueField', ['message' => t('The username %value is already taken.')]);
    * @endcode
    *
    * If you wish to apply a constraint to a \Drupal\Core\Field\FieldItem instead
diff --git a/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/UniqueFieldConstraint.php b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/UniqueFieldConstraint.php
new file mode 100644
index 0000000..da58934
--- /dev/null
+++ b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/UniqueFieldConstraint.php
@@ -0,0 +1,31 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Validation\Plugin\Validation\Constraint\UniqueFieldConstraint.
+ */
+
+namespace Drupal\Core\Validation\Plugin\Validation\Constraint;
+
+use Symfony\Component\Validator\Constraint;
+
+/**
+ * Checks if an entity field has a unique value.
+ *
+ * @Plugin(
+ *   id = "UniqueField",
+ *   label = @Translation("Unique field constraint", context = "Validation"),
+ * )
+ */
+class UniqueFieldConstraint extends Constraint {
+
+  public $message = 'A @entity_type with the @field_name %value already exists.';
+
+  /**
+   * {@inheritdoc}
+   */
+  public function validatedBy() {
+    return '\Drupal\Core\Validation\Plugin\Validation\Constraint\UniqueFieldValueValidator';
+  }
+
+}
diff --git a/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/UniqueFieldValueValidator.php b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/UniqueFieldValueValidator.php
index d6c3910..1917c5c 100644
--- a/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/UniqueFieldValueValidator.php
+++ b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/UniqueFieldValueValidator.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\Core\Validation\Plugin\Validation\Constraint;
 
+use Drupal\Component\Utility\Unicode;
 use Symfony\Component\Validator\Constraint;
 use Symfony\Component\Validator\ConstraintValidator;
 
@@ -37,7 +38,11 @@ public function validate($items, Constraint $constraint) {
       ->execute();
 
     if ($value_taken) {
-      $this->context->addViolation($constraint->message, array("%value" => $item->value));
+      $this->context->addViolation($constraint->message, [
+        '%value' => $item->value,
+        '@entity_type' => $entity->getEntityType()->getLowercaseLabel(),
+        '@field_name' => Unicode::strtolower($items->getFieldDefinition()->getLabel()),
+      ]);
     }
   }
 }
diff --git a/core/modules/aggregator/src/Entity/Feed.php b/core/modules/aggregator/src/Entity/Feed.php
index a5ed081..fc1b9ee 100644
--- a/core/modules/aggregator/src/Entity/Feed.php
+++ b/core/modules/aggregator/src/Entity/Feed.php
@@ -151,7 +151,7 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
         'weight' => -5,
       ))
       ->setDisplayConfigurable('form', TRUE)
-      ->addConstraint('FeedTitle', []);
+      ->addConstraint('UniqueField', ['message' => t('A feed named %value already exists. Enter a unique title.')]);
 
     $fields['langcode'] = BaseFieldDefinition::create('language')
       ->setLabel(t('Language code'))
@@ -173,7 +173,7 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
         'weight' => -3,
       ))
       ->setDisplayConfigurable('form', TRUE)
-      ->addConstraint('FeedUrl', []);
+      ->addConstraint('UniqueField', ['message' => t('A feed with this URL %value already exists. Enter a unique URL.')]);
 
     $intervals = array(900, 1800, 3600, 7200, 10800, 21600, 32400, 43200, 64800, 86400, 172800, 259200, 604800, 1209600, 2419200);
     $period = array_map(array(\Drupal::service('date.formatter'), 'formatInterval'), array_combine($intervals, $intervals));
diff --git a/core/modules/aggregator/src/Plugin/Validation/Constraint/FeedTitleConstraint.php b/core/modules/aggregator/src/Plugin/Validation/Constraint/FeedTitleConstraint.php
deleted file mode 100644
index 47d16ac..0000000
--- a/core/modules/aggregator/src/Plugin/Validation/Constraint/FeedTitleConstraint.php
+++ /dev/null
@@ -1,31 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\aggregator\Plugin\Validation\Constraint\FeedTitleConstraint.
- */
-
-namespace Drupal\aggregator\Plugin\Validation\Constraint;
-
-use Symfony\Component\Validator\Constraint;
-
-/**
- * Supports validating feed titles.
- *
- * @Plugin(
- *   id = "FeedTitle",
- *   label = @Translation("Feed title", context = "Validation")
- * )
- */
-class FeedTitleConstraint extends Constraint {
-
-  public $message = 'A feed named %value already exists. Enter a unique title.';
-
-  /**
-   * {@inheritdoc}
-   */
-  public function validatedBy() {
-    return '\Drupal\Core\Validation\Plugin\Validation\Constraint\UniqueFieldValueValidator';
-  }
-
-}
diff --git a/core/modules/aggregator/src/Plugin/Validation/Constraint/FeedUrlConstraint.php b/core/modules/aggregator/src/Plugin/Validation/Constraint/FeedUrlConstraint.php
deleted file mode 100644
index 0e2ce1d..0000000
--- a/core/modules/aggregator/src/Plugin/Validation/Constraint/FeedUrlConstraint.php
+++ /dev/null
@@ -1,31 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\aggregator\Plugin\Validation\Constraint\FeedUrlConstraint.
- */
-
-namespace Drupal\aggregator\Plugin\Validation\Constraint;
-
-use Symfony\Component\Validator\Constraint;
-
-/**
- * Supports validating feed URLs.
- *
- * @Plugin(
- *   id = "FeedUrl",
- *   label = @Translation("Feed URL", context = "Validation")
- * )
- */
-class FeedUrlConstraint extends Constraint {
-
-  public $message = 'A feed with this URL %value already exists. Enter a unique URL.';
-
-  /**
-   * {@inheritdoc}
-   */
-  public function validatedBy() {
-    return '\Drupal\Core\Validation\Plugin\Validation\Constraint\UniqueFieldValueValidator';
-  }
-
-}
diff --git a/core/modules/block_content/src/BlockContentForm.php b/core/modules/block_content/src/BlockContentForm.php
index 379e576..088c4d7 100644
--- a/core/modules/block_content/src/BlockContentForm.php
+++ b/core/modules/block_content/src/BlockContentForm.php
@@ -220,18 +220,4 @@ public function save(array $form, FormStateInterface $form_state) {
     }
   }
 
-  /**
-   * {@inheritdoc}
-   */
-  public function validateForm(array &$form, FormStateInterface $form_state) {
-    if ($this->entity->isNew()) {
-      $exists = $this->blockContentStorage->loadByProperties(array('info' => $form_state->getValue(['info', 0, 'value'])));
-      if (!empty($exists)) {
-        $form_state->setErrorByName('info', $this->t('A block with description %name already exists.', array(
-          '%name' => $form_state->getValue(array('info', 0, 'value')),
-        )));
-      }
-    }
-  }
-
 }
diff --git a/core/modules/block_content/src/Entity/BlockContent.php b/core/modules/block_content/src/Entity/BlockContent.php
index 046640c..ec57d5b 100644
--- a/core/modules/block_content/src/Entity/BlockContent.php
+++ b/core/modules/block_content/src/Entity/BlockContent.php
@@ -187,7 +187,8 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
         'type' => 'string_textfield',
         'weight' => -5,
       ))
-      ->setDisplayConfigurable('form', TRUE);
+      ->setDisplayConfigurable('form', TRUE)
+      ->addConstraint('UniqueField', ['message' => t('A block with description %value already exists.')]);
 
     $fields['type'] = BaseFieldDefinition::create('entity_reference')
       ->setLabel(t('Block type'))
diff --git a/core/modules/block_content/src/Tests/BlockContentCreationTest.php b/core/modules/block_content/src/Tests/BlockContentCreationTest.php
index 6bf250c..7afb177 100644
--- a/core/modules/block_content/src/Tests/BlockContentCreationTest.php
+++ b/core/modules/block_content/src/Tests/BlockContentCreationTest.php
@@ -66,8 +66,8 @@ public function testBlockContentCreation() {
     $this->drupalPostForm('block/add/basic', $edit, t('Save'));
 
     // Check that the Basic block has been created.
-    $this->assertRaw(format_string('A block with description %name already exists.', array(
-      '%name' => $edit['info[0][value]']
+    $this->assertRaw(format_string('A block with description %value already exists.', array(
+      '%value' => $edit['info[0][value]']
     )));
     $this->assertResponse(200);
   }
@@ -124,8 +124,8 @@ public function testBlockContentCreationMultipleViewModes() {
     $this->drupalPostForm('block/add/basic', $edit, t('Save'));
 
     // Check that the Basic block has been created.
-    $this->assertRaw(format_string('A block with description %name already exists.', array(
-      '%name' => $edit['info[0][value]']
+    $this->assertRaw(format_string('A block with description %value already exists.', array(
+      '%value' => $edit['info[0][value]']
     )));
     $this->assertResponse(200);
   }
diff --git a/core/modules/block_content/src/Tests/BlockContentTestBase.php b/core/modules/block_content/src/Tests/BlockContentTestBase.php
index 82139c0..9cff6c0 100644
--- a/core/modules/block_content/src/Tests/BlockContentTestBase.php
+++ b/core/modules/block_content/src/Tests/BlockContentTestBase.php
@@ -70,17 +70,20 @@ protected function setUp() {
    *   Defaults to FALSE.
    * @param string $bundle
    *   (optional) Bundle name. Defaults to 'basic'.
+   * @param bool $save
+   *   (optional) Whether to save the block. Defaults to TRUE.
    *
    * @return \Drupal\block_content\Entity\BlockContent
    *   Created custom block.
    */
-  protected function createBlockContent($title = FALSE, $bundle = 'basic') {
+  protected function createBlockContent($title = FALSE, $bundle = 'basic', $save = TRUE) {
     $title = ($title ? : $this->randomMachineName());
-    if ($block_content = entity_create('block_content', array(
+    $block_content = entity_create('block_content', array(
       'info' => $title,
       'type' => $bundle,
       'langcode' => 'en'
-    ))) {
+    ));
+    if ($block_content && $save === TRUE) {
       $block_content->save();
     }
     return $block_content;
diff --git a/core/modules/block_content/src/Tests/BlockContentValidationTest.php b/core/modules/block_content/src/Tests/BlockContentValidationTest.php
new file mode 100644
index 0000000..85bf6e9
--- /dev/null
+++ b/core/modules/block_content/src/Tests/BlockContentValidationTest.php
@@ -0,0 +1,45 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\block_content\Tests\BlockContentValidationTest.
+ */
+
+namespace Drupal\block_content\Tests;
+
+/**
+ * Tests block content validation constraints.
+ *
+ * @group block_content
+ */
+class BlockContentValidationTest extends BlockContentTestBase {
+
+  /**
+   * Tests the block content validation constraints.
+   */
+  public function testValidation() {
+    // Add a block.
+    $description = $this->randomMachineName();
+    $block = $this->createBlockContent($description, 'basic', FALSE);
+    // Validate the block.
+    $violations = $block->validate();
+    // Make sure we have no violations.
+    $this->assertEqual(count($violations), 0);
+    // Save the block.
+    $block->save();
+
+    // Add another block with the same description.
+    $block = $this->createBlockContent($description, 'basic', FALSE);
+    // Validate this block.
+    $violations = $block->validate();
+    // Make sure we have 1 violation.
+    $this->assertEqual(count($violations), 1);
+    // Make sure the violation is on the info property
+    $this->assertEqual($violations[0]->getPropertyPath(), 'info');
+    // Make sure the message is correct.
+    $this->assertEqual($violations[0]->getMessage(), format_string('A block with description %value already exists.', [
+      '%value' => $block->label(),
+    ]));
+  }
+
+}
diff --git a/core/modules/user/src/Entity/User.php b/core/modules/user/src/Entity/User.php
index fa4db6f..7e0b0de 100644
--- a/core/modules/user/src/Entity/User.php
+++ b/core/modules/user/src/Entity/User.php
@@ -465,7 +465,7 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
         // No Length constraint here because the UserName constraint also covers
         // that.
         'UserName' => array(),
-        'UserNameUnique' => array(),
+        'UniqueField' => array('message' => t('The username %value is already taken.')),
       ));
 
     $fields['pass'] = BaseFieldDefinition::create('password')
@@ -477,7 +477,7 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
       ->setLabel(t('Email'))
       ->setDescription(t('The email of this user.'))
       ->setDefaultValue('')
-      ->addConstraint('UserMailUnique')
+      ->addConstraint('UniqueField', ['message' => t('The email address %value is already taken.')])
       ->addConstraint('UserMailRequired')
       ->addConstraint('ProtectedUserField');
 
diff --git a/core/modules/user/src/Plugin/Validation/Constraint/UserMailUnique.php b/core/modules/user/src/Plugin/Validation/Constraint/UserMailUnique.php
deleted file mode 100644
index e541518..0000000
--- a/core/modules/user/src/Plugin/Validation/Constraint/UserMailUnique.php
+++ /dev/null
@@ -1,30 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\user\Plugin\Validation\Constraint\UserMailUnique.
- */
-
-namespace Drupal\user\Plugin\Validation\Constraint;
-
-use Symfony\Component\Validator\Constraint;
-
-/**
- * Checks if a user's email address is unique on the site.
- *
- * @Plugin(
- *   id = "UserMailUnique",
- *   label = @Translation("User email unique", context = "Validation")
- * )
- */
-class UserMailUnique extends Constraint {
-
-  public $message = 'The email address %value is already taken.';
-
-  /**
-   * {@inheritdoc}
-   */
-  public function validatedBy() {
-    return '\Drupal\Core\Validation\Plugin\Validation\Constraint\UniqueFieldValueValidator';
-  }
-}
diff --git a/core/modules/user/src/Plugin/Validation/Constraint/UserNameUnique.php b/core/modules/user/src/Plugin/Validation/Constraint/UserNameUnique.php
deleted file mode 100644
index 0a65d32..0000000
--- a/core/modules/user/src/Plugin/Validation/Constraint/UserNameUnique.php
+++ /dev/null
@@ -1,30 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\user\Plugin\Validation\Constraint\UserNameUnique.
- */
-
-namespace Drupal\user\Plugin\Validation\Constraint;
-
-use Symfony\Component\Validator\Constraint;
-
-/**
- * Checks if a user name is unique on the site.
- *
- * @Plugin(
- *   id = "UserNameUnique",
- *   label = @Translation("User name unique", context = "Validation"),
- * )
- */
-class UserNameUnique extends Constraint {
-
-  public $message = 'The username %value is already taken.';
-
-  /**
-   * {@inheritdoc}
-   */
-  public function validatedBy() {
-    return '\Drupal\Core\Validation\Plugin\Validation\Constraint\UniqueFieldValueValidator';
-  }
-}
