diff --git a/core/modules/user/src/AccountForm.php b/core/modules/user/src/AccountForm.php
index 7ed3cbd..f3e1740 100644
--- a/core/modules/user/src/AccountForm.php
+++ b/core/modules/user/src/AccountForm.php
@@ -359,7 +359,15 @@ public function buildEntity(array $form, FormStateInterface $form_state) {
     if (is_string(key($form_state->getValue('roles')))) {
       $form_state->setValue('roles', array_keys(array_filter($form_state->getValue('roles'))));
     }
-    return parent::buildEntity($form, $form_state);
+
+    /** @var \Drupal\user\UserInterface $account */
+    $account = parent::buildEntity($form, $form_state);
+
+    $signature = $form_state->getValue('signature');
+    $account->setSignature($signature['value']);
+    $account->setSignatureFormat($signature['format']);
+
+    return $account;
   }
 
   /**
@@ -368,64 +376,23 @@ public function buildEntity(array $form, FormStateInterface $form_state) {
   public function validate(array $form, FormStateInterface $form_state) {
     parent::validate($form, $form_state);
 
-    $account = $this->entity;
-    // Validate new or changing username.
-    if ($form_state->hasValue('name')) {
-      if ($error = user_validate_name($form_state->getValue('name'))) {
-        $form_state->setErrorByName('name', $error);
-      }
-      // Cast the user ID as an integer. It might have been set to NULL, which
-      // could lead to unexpected results.
-      else {
-        $name_taken = (bool) $this->entityQuery->get('user')
-          ->condition('uid', (int) $account->id(), '<>')
-          ->condition('name', $form_state->getValue('name'))
-          ->range(0, 1)
-          ->count()
-          ->execute();
-
-        if ($name_taken) {
-          $form_state->setErrorByName('name', $this->t('The username %name is already taken.', array('%name' => $form_state->getValue('name'))));
-        }
-      }
+    /** @var \Drupal\user\UserInterface $account */
+    $account = $this->buildEntity($form, $form_state);
+    // Customly trigger validation of manually added fields and add in
+    // violations.
+    $violations = $account->name->validate();
+    foreach ($violations as $violation) {
+      $form_state->setErrorByName('name', $violation->getMessage());
     }
 
-    $mail = $form_state->getValue('mail');
-
-    if (!empty($mail)) {
-      $mail_taken = (bool) $this->entityQuery->get('user')
-        ->condition('uid', (int) $account->id(), '<>')
-        ->condition('mail', $mail)
-        ->range(0, 1)
-        ->count()
-        ->execute();
-
-      if ($mail_taken) {
-        // Format error message dependent on whether the user is logged in or not.
-        if (\Drupal::currentUser()->isAuthenticated()) {
-          $form_state->setErrorByName('mail', $this->t('The email address %email is already taken.', array('%email' => $mail)));
-        }
-        else {
-          $form_state->setErrorByName('mail', $this->t('The email address %email is already registered. <a href="@password">Have you forgotten your password?</a>', array('%email' => $mail, '@password' => $this->url('user.pass'))));
-        }
-      }
+    $violations = $account->mail->validate();
+    foreach ($violations as $violation) {
+      $form_state->setErrorByName('mail', $violation->getMessage());
     }
 
-    // Make sure the signature isn't longer than the size of the database field.
-    // Signatures are disabled by default, so make sure it exists first.
-    if ($signature = $form_state->getValue('signature')) {
-      // Move text format for user signature into 'signature_format'.
-      $form_state->setValue('signature_format', $signature['format']);
-      // Move text value for user signature into 'signature'.
-      $form_state->setValue('signature', $signature['value']);
-
-      // @todo Make the user signature field use a widget to benefit from
-      //   automatic typed data validation in https://drupal.org/node/2227381.
-      $field_definitions = $this->entityManager->getFieldDefinitions('user', $this->getEntity()->bundle());
-      $max_length = $field_definitions['signature']->getSetting('max_length');
-      if (Unicode::strlen($form_state->getValue('signature')) > $max_length) {
-        $form_state->setErrorByName('signature', $this->t('The signature is too long: it must be %max characters or less.', array('%max' => $max_length)));
-      }
+    $violations = $account->signature->validate();
+    foreach ($violations as $violation) {
+      $form_state->setErrorByName('signature', $violation->getMessage());
     }
   }
 
diff --git a/core/modules/user/src/Entity/User.php b/core/modules/user/src/Entity/User.php
index 81386d7..7f50f89 100644
--- a/core/modules/user/src/Entity/User.php
+++ b/core/modules/user/src/Entity/User.php
@@ -291,6 +291,14 @@ public function getSignature() {
   /**
    * {@inheritdoc}
    */
+  public function setSignature($signature) {
+    $this->get('signature')->value = $signature;
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   public function getSignatureFormat() {
     return $this->get('signature_format')->value;
   }
@@ -298,6 +306,14 @@ public function getSignatureFormat() {
   /**
    * {@inheritdoc}
    */
+  public function setSignatureFormat($signature_format) {
+    $this->get('signature_format')->value = $signature_format;
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   public function getCreatedTime() {
     return $this->get('created')->value;
   }
@@ -496,7 +512,8 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
     $fields['signature'] = BaseFieldDefinition::create('string')
       ->setLabel(t('Signature'))
       ->setDescription(t('The signature of this user.'))
-      ->setTranslatable(TRUE);
+      ->setTranslatable(TRUE)
+      ->setConstraints(array('UserSignature' => array()));
     $fields['signature_format'] = BaseFieldDefinition::create('string')
       ->setLabel(t('Signature format'))
       ->setDescription(t('The signature format of this user.'));
diff --git a/core/modules/user/src/Plugin/Validation/Constraint/UserSignatureConstraint.php b/core/modules/user/src/Plugin/Validation/Constraint/UserSignatureConstraint.php
new file mode 100644
index 0000000..7fe663b
--- /dev/null
+++ b/core/modules/user/src/Plugin/Validation/Constraint/UserSignatureConstraint.php
@@ -0,0 +1,23 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\user\Plugin\Validation\Constraint\UserSignatureConstraint.
+ */
+
+namespace Drupal\user\Plugin\Validation\Constraint;
+
+use Symfony\Component\Validator\Constraint;
+
+/**
+ * Checks if a value is a valid user signature.
+ *
+ * @Plugin(
+ *   id = "UserSignature",
+ *   label = @Translation("User signature", context = "Validation"),
+ * )
+ */
+class UserSignatureConstraint extends Constraint {
+
+  public $tooLongMessage = 'The signature is too long: it must be %max characters or less.';
+}
diff --git a/core/modules/user/src/Plugin/Validation/Constraint/UserSignatureConstraintValidator.php b/core/modules/user/src/Plugin/Validation/Constraint/UserSignatureConstraintValidator.php
new file mode 100644
index 0000000..273ba96
--- /dev/null
+++ b/core/modules/user/src/Plugin/Validation/Constraint/UserSignatureConstraintValidator.php
@@ -0,0 +1,33 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\user\Plugin\Validation\Constraint\UserSignatureConstraintValidator.
+ */
+
+namespace Drupal\user\Plugin\Validation\Constraint;
+
+use Drupal\Component\Utility\Unicode;
+use Symfony\Component\Validator\Constraint;
+use Symfony\Component\Validator\ConstraintValidator;
+
+/**
+ * Validates the UserSignature constraint.
+ */
+class UserSignatureConstraintValidator extends ConstraintValidator {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function validate($items, Constraint $constraint) {
+    // Don't validate empty signature.
+    if (isset($items)) {
+      $max_length = $items->getFieldDefinition()->getSetting('max_length');
+
+      if (Unicode::strlen($items->value) > $max_length) {
+        $this->context->addViolation($constraint->tooLongMessage, array('%max' => $max_length));
+        return;
+      }
+    }
+  }
+}
diff --git a/core/modules/user/src/Tests/UserValidationTest.php b/core/modules/user/src/Tests/UserValidationTest.php
index f5ae202..47dd1c2 100644
--- a/core/modules/user/src/Tests/UserValidationTest.php
+++ b/core/modules/user/src/Tests/UserValidationTest.php
@@ -129,8 +129,15 @@ function testValidation() {
     $this->assertEqual($violations[0]->getMessage(), t('The email address %mail is already taken.', array('%mail' => 'existing@example.com')));
     $user->set('mail', NULL);
 
+    $max_signature_length = $user->get('signature')->getFieldDefinition()->getSetting('max_length');
+
     $user->set('signature', $this->randomString(256));
-    $this->assertLengthViolation($user, 'signature', 255);
+    $violations = $user->validate();
+    $this->assertEqual(count($violations), 2, 'Violation found when signature is too long.');
+    $this->assertEqual($violations[0]->getPropertyPath(), 'signature');
+    $this->assertEqual($violations[0]->getMessage(), t('The signature is too long: it must be %max characters or less.', array('%max' => $max_signature_length)));
+    $this->assertEqual($violations[1]->getPropertyPath(), 'signature.0.value');
+    $this->assertEqual($violations[1]->getMessage(), t('%name: may not be longer than @max characters.', array('@max' => $max_signature_length, '%name' => $user->get('signature')->getFieldDefinition()->getLabel())));
     $user->set('signature', NULL);
 
     $user->set('timezone', $this->randomString(33));
diff --git a/core/modules/user/src/UserInterface.php b/core/modules/user/src/UserInterface.php
index e2c44d0..6ccad91 100644
--- a/core/modules/user/src/UserInterface.php
+++ b/core/modules/user/src/UserInterface.php
@@ -97,6 +97,19 @@ public function setEmail($mail);
   public function getSignature();
 
   /**
+   * Set the user signature.
+   *
+   * @todo: Convert this to a configurable field.
+   *
+   * @param string $signature
+   *   The new signature text of the user.
+   *
+   * @return \Drupal\user\UserInterface
+   *   The called user entity.
+   */
+  public function setSignature($signature);
+
+  /**
    * Returns the signature format.
    *
    * @return string
@@ -105,6 +118,17 @@ public function getSignature();
   public function getSignatureFormat();
 
   /**
+   * Set the signature format.
+   *
+   * @param string
+   *   The name of the new filter format.
+   *
+   * @return \Drupal\user\UserInterface
+   *   The called user entity.
+   */
+  public function setSignatureFormat($signature_format);
+
+  /**
    * Returns the creation time of the user as a UNIX timestamp.
    *
    * @return int
