diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/PasswordWidget.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/PasswordWidget.php
new file mode 100644
index 0000000..7c6e79e
--- /dev/null
+++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/PasswordWidget.php
@@ -0,0 +1,41 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Field\Plugin\Field\FieldWidget\PasswordWidget.
+ */
+
+namespace Drupal\Core\Field\Plugin\Field\FieldWidget;
+
+use Drupal\Core\Field\FieldItemListInterface;
+use Drupal\Core\Field\WidgetBase;
+
+/**
+ * Plugin implementation of the 'password' widget.
+ *
+ * @FieldWidget(
+ *   id = "password",
+ *   label = @Translation("Password field"),
+ *   field_types = {
+ *     "string"
+ *   },
+ *   settings = {
+ *     "size" = ""
+ *   }
+ * )
+ */
+class PasswordWidget extends WidgetBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, array &$form_state) {
+    $element['value'] = $element + array(
+      '#type' => 'password_confirm',
+      '#size' => $this->getSetting('size'),
+    );
+    $element['value']['#description'] = $this->t('To change the current user password, enter the new password in both fields.');
+
+    return $element;
+  }
+}
diff --git a/core/modules/dblog/lib/Drupal/dblog/Tests/DbLogTest.php b/core/modules/dblog/lib/Drupal/dblog/Tests/DbLogTest.php
index 850b6e1..e28b69a 100644
--- a/core/modules/dblog/lib/Drupal/dblog/Tests/DbLogTest.php
+++ b/core/modules/dblog/lib/Drupal/dblog/Tests/DbLogTest.php
@@ -220,7 +220,7 @@ private function doUser() {
     // Add a user using the form to generate an add user event (which is not
     // triggered by drupalCreateUser).
     $edit = array();
-    $edit['name'] = $name;
+    $edit['name'][0]['value'] = $name;
     $edit['mail'] = $name . '@example.com';
     $edit['pass[pass1]'] = $pass;
     $edit['pass[pass2]'] = $pass;
diff --git a/core/modules/user/lib/Drupal/user/AccountFormController.php b/core/modules/user/lib/Drupal/user/AccountFormController.php
index ed4cc07..de06383 100644
--- a/core/modules/user/lib/Drupal/user/AccountFormController.php
+++ b/core/modules/user/lib/Drupal/user/AccountFormController.php
@@ -69,6 +69,9 @@ public static function create(ContainerInterface $container) {
   public function form(array $form, array &$form_state) {
     /** @var \Drupal\user\UserInterface $account */
     $account = $this->entity;
+
+    $form = parent::form($form, $form_state, $account);
+
     $user = $this->currentUser();
     $config = \Drupal::config('user.settings');
 
@@ -82,40 +85,13 @@ public function form(array $form, array &$form_state) {
       '#weight' => -10,
     );
 
-    // Only show name field on registration form or user can change own username.
-    $form['account']['name'] = array(
-      '#type' => 'textfield',
-      '#title' => $this->t('Username'),
-      '#maxlength' => USERNAME_MAX_LENGTH,
-      '#description' => $this->t('Spaces are allowed; punctuation is not allowed except for periods, hyphens, apostrophes, and underscores.'),
-      '#required' => TRUE,
-      '#attributes' => array('class' => array('username'), 'autocorrect' => 'off', 'autocomplete' => 'off', 'autocapitalize' => 'off',
-      'spellcheck' => 'false'),
-      '#default_value' => (!$register ? $account->getUsername() : ''),
-      '#access' => ($register || ($user->id() == $account->id() && $user->hasPermission('change own username')) || $admin),
-      '#weight' => -10,
-    );
-
-    // The mail field is NOT required if account originally had no mail set
-    // and the user performing the edit has 'administer users' permission.
-    // This allows users without e-mail address to be edited and deleted.
-    $form['account']['mail'] = array(
-      '#type' => 'email',
-      '#title' => $this->t('E-mail address'),
-      '#description' => $this->t('A valid e-mail address. All e-mails from the system will be sent to this address. The e-mail address is not made public and will only be used if you wish to receive a new password or wish to receive certain news or notifications by e-mail.'),
-      '#required' => !(!$account->getEmail() && $user->hasPermission('administer users')),
-      '#default_value' => (!$register ? $account->getEmail() : ''),
-      '#attributes' => array('autocomplete' => 'off'),
-    );
+    $form['name']['#group'] = 'account';
+    $form['mail']['#group'] = 'account';
 
     // Display password field only for existing users or when user is allowed to
     // assign a password during registration.
     if (!$register) {
-      $form['account']['pass'] = array(
-        '#type' => 'password_confirm',
-        '#size' => 25,
-        '#description' => $this->t('To change the current user password, enter the new password in both fields.'),
-      );
+      $form['pass']['#group'] = 'account';
 
       // To skip the current password field, the user must have logged in via a
       // one-time link and have the token in the URL.
@@ -127,7 +103,7 @@ public function form(array $form, array &$form_state) {
       // The user may only change their own password without their current
       // password if they logged in via a one-time login link.
       if (!$pass_reset) {
-        $protected_values['mail'] = $form['account']['mail']['#title'];
+        $protected_values['mail'] = $this->t('E-mail address');
         $protected_values['pass'] = $this->t('Password');
         $request_new = l($this->t('Request new password'), 'user/password', array('attributes' => array('title' => $this->t('Request new password via e-mail.'))));
         $current_pass_description = $this->t('Required if you want to change the %mail or %pass below. !request_new.', array('%mail' => $protected_values['mail'], '%pass' => $protected_values['pass'], '!request_new' => $request_new));
@@ -290,7 +266,7 @@ public function form(array $form, array &$form_state) {
       '#weight' => 100,
     );
 
-    return parent::form($form, $form_state, $account);
+    return $form;
   }
 
   /**
@@ -315,49 +291,6 @@ public function buildEntity(array $form, array &$form_state) {
   public function validate(array $form, array &$form_state) {
     parent::validate($form, $form_state);
 
-    $account = $this->entity;
-    // Validate new or changing username.
-    if (isset($form_state['values']['name'])) {
-      if ($error = user_validate_name($form_state['values']['name'])) {
-        $this->setFormError('name', $form_state, $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['values']['name'])
-          ->range(0, 1)
-          ->count()
-          ->execute();
-
-        if ($name_taken) {
-          $this->setFormError('name', $form_state, $this->t('The name %name is already taken.', array('%name' => $form_state['values']['name'])));
-        }
-      }
-    }
-
-    $mail = $form_state['values']['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()) {
-          $this->setFormError('mail', $form_state, $this->t('The e-mail address %email is already taken.', array('%email' => $mail)));
-        }
-        else {
-          $this->setFormError('mail', $form_state, $this->t('The e-mail address %email is already registered. <a href="@password">Have you forgotten your password?</a>', array('%email' => $mail, '@password' => url('user/password'))));
-        }
-      }
-    }
-
     // 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 (isset($form_state['values']['signature'])) {
diff --git a/core/modules/user/lib/Drupal/user/Entity/User.php b/core/modules/user/lib/Drupal/user/Entity/User.php
index 8bb2f51..b057e6b 100644
--- a/core/modules/user/lib/Drupal/user/Entity/User.php
+++ b/core/modules/user/lib/Drupal/user/Entity/User.php
@@ -456,14 +456,17 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
       ->setDescription(t('The user UUID.'))
       ->setReadOnly(TRUE);
 
+    // @todo Use LanguageWidget once https://drupal.org/node/2226493 lands.
     $fields['langcode'] = FieldDefinition::create('language')
       ->setLabel(t('Language code'))
       ->setDescription(t('The user language code.'));
 
+    // @todo Use LanguageWidget once https://drupal.org/node/2226493 lands.
     $fields['preferred_langcode'] = FieldDefinition::create('language')
       ->setLabel(t('Preferred admin language code'))
       ->setDescription(t("The user's preferred language code for receiving emails and viewing the site."));
 
+    // @todo Use LanguageWidget once https://drupal.org/node/2226493 lands.
     $fields['preferred_admin_langcode'] = FieldDefinition::create('language')
       ->setLabel(t('Preferred language code'))
       ->setDescription(t("The user's preferred language code for viewing administration pages."));
@@ -471,25 +474,43 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
     // The name should not vary per language. The username is the visual
     // identifier for a user and needs to be consistent in all languages.
     $fields['name'] = FieldDefinition::create('string')
-      ->setLabel(t('Name'))
+      ->setLabel(t('Username'))
       ->setDescription(t('The name of this user.'))
-      ->setSetting('default_value', '')
+      ->setRequired(TRUE)
+      ->setSettings(array(
+        'default_value' => '',
+        'max_length' => USERNAME_MAX_LENGTH,
+      ))
       ->setPropertyConstraints('value', array(
-        // No Length constraint here because the UserName constraint also covers
-        // that.
         'UserName' => array(),
         'UserNameUnique' => array(),
+      ))
+      ->setDisplayOptions('form', array(
+        'type' => 'username',
+        'weight' => -20,
       ));
 
     $fields['pass'] = FieldDefinition::create('string')
       ->setLabel(t('Password'))
-      ->setDescription(t('The password of this user (hashed).'));
+      ->setDescription(t('The password of this user (hashed).'))
+      ->setDisplayOptions('form', array(
+        'type' => 'password',
+        'weight' => 0,
+        'settings' => array(
+          'size' => 25,
+        ),
+      ));
 
     $fields['mail'] = FieldDefinition::create('email')
-      ->setLabel(t('Email'))
+      ->setLabel(t('E-mail address'))
       ->setDescription(t('The email of this user.'))
       ->setSetting('default_value', '')
-      ->setPropertyConstraints('value', array('UserMailUnique' => array()));
+      ->setPropertyConstraints('value', array('UserMailUnique' => array()))
+      ->setDisplayOptions('form', array(
+        'type' => 'email_user',
+        'weight' => -10,
+      ))
+      ->setDisplayConfigurable('form', TRUE);
 
     // @todo Convert to a text field in https://drupal.org/node/1548204.
     $fields['signature'] = FieldDefinition::create('string')
diff --git a/core/modules/user/lib/Drupal/user/Plugin/Field/FieldWidget/EmailUserWidget.php b/core/modules/user/lib/Drupal/user/Plugin/Field/FieldWidget/EmailUserWidget.php
new file mode 100644
index 0000000..5e3e69b
--- /dev/null
+++ b/core/modules/user/lib/Drupal/user/Plugin/Field/FieldWidget/EmailUserWidget.php
@@ -0,0 +1,47 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\user\Plugin\Field\FieldWidget\EmailUserWidget.
+ */
+
+namespace Drupal\user\Plugin\Field\FieldWidget;
+
+use Drupal\Core\Field\FieldItemListInterface;
+use Drupal\Core\Field\WidgetBase;
+
+/**
+ * Plugin implementation of the 'email_user' widget.
+ *
+ * @FieldWidget(
+ *   id = "email_user",
+ *   label = @Translation("User e-mail"),
+ *   field_types = {
+ *     "email"
+ *   }
+ * )
+ */
+class EmailUserWidget extends WidgetBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, array &$form_state) {
+    $account = $element['#entity'];
+    $user = \Drupal::currentUser();
+
+    $element['value'] = $element + array(
+      '#type' => 'email',
+      '#description' => $this->t('A valid e-mail address. All e-mails from the system will be sent to this address. The e-mail address is not made public and will only be used if you wish to receive a new password or wish to receive certain news or notifications by e-mail.'),
+      // The mail field is NOT required if account originally had no mail set
+      // and the user performing the edit has 'administer users' permission.
+      // This allows users without e-mail address to be edited and deleted.
+      '#required' => !(!$account->getEmail() && $user->hasPermission('administer users')),
+      '#default_value' => (!$account->isAnonymous() ? $account->getEmail() : ''),
+      '#attributes' => array('autocomplete' => 'off'),
+    );
+
+    return $element;
+  }
+
+}
diff --git a/core/modules/user/lib/Drupal/user/Plugin/Field/FieldWidget/UserNameWidget.php b/core/modules/user/lib/Drupal/user/Plugin/Field/FieldWidget/UserNameWidget.php
new file mode 100644
index 0000000..d7798be
--- /dev/null
+++ b/core/modules/user/lib/Drupal/user/Plugin/Field/FieldWidget/UserNameWidget.php
@@ -0,0 +1,58 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Field\Plugin\Field\FieldWidget\StringWidget.
+ */
+
+namespace Drupal\user\Plugin\Field\FieldWidget;
+
+use Drupal\Core\Field\FieldItemListInterface;
+use Drupal\Core\Field\WidgetBase;
+
+/**
+ * Plugin implementation of the 'user name' widget.
+ *
+ * @FieldWidget(
+ *   id = "username",
+ *   label = @Translation("User name field"),
+ *   field_types = {
+ *     "string"
+ *   }
+ * )
+ */
+class UserNameWidget extends WidgetBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, array &$form_state) {
+    $account = $element['#entity'];
+    $user = \Drupal::currentUser();
+
+    $is_anon = $account->isAnonymous();
+    $is_admin = $user->hasPermission('administer users');;
+
+    $element['value'] = $element + array(
+      '#type' => 'textfield',
+      '#default_value' => isset($items[$delta]->value) ? $items[$delta]->value : NULL,
+      '#size' => $this->getSetting('size'),
+      '#maxlength' => $this->getFieldSetting('max_length'),
+      '#attributes' => array(
+        'class' => array('username'),
+        'autocorrect' => 'off',
+        'autocomplete' => 'off',
+        'autocapitalize' => 'off',
+        'spellcheck' => 'false',
+      ),
+      '#default_value' => (!$is_anon ? $account->getUsername() : ''),
+      // Only show name field on registration form or user can change own
+      // username.
+      '#access' => ($is_anon || ($user->id() == $account->id() && $user->hasPermission('change own username')) || $is_admin),
+    );
+    $element['value']['#description'] = $this->t('Spaces are allowed; punctuation is not allowed except for periods, hyphens, apostrophes, and underscores.');
+
+    return $element;
+  }
+
+}
diff --git a/core/modules/user/user.module b/core/modules/user/user.module
index 965167e..42d6790 100644
--- a/core/modules/user/user.module
+++ b/core/modules/user/user.module
@@ -536,7 +536,7 @@ function user_validate_current_pass(&$form, &$form_state) {
     // form values like password_confirm that have their own validation
     // that prevent them from being empty if they are changed.
     $current_value = $account->hasField($key) ? $account->get($key)->value : $account->$key;
-    if ((strlen(trim($form_state['values'][$key])) > 0) && ($form_state['values'][$key] != $current_value)) {
+    if ((strlen(trim($form_state['values'][$key][0]['value'])) > 0) && ($form_state['values'][$key][0]['value'] != $current_value)) {
       $current_pass_failed = empty($form_state['values']['current_pass']) || !\Drupal::service('password')->check($form_state['values']['current_pass'], $account);
       if ($current_pass_failed) {
         form_set_error('current_pass', $form_state, t("Your current password is missing or incorrect; it's required to change the %name.", array('%name' => $name)));
