diff --git a/core/includes/install.core.inc b/core/includes/install.core.inc
index b1d3b50..fc3460b 100644
--- a/core/includes/install.core.inc
+++ b/core/includes/install.core.inc
@@ -1612,7 +1612,7 @@ function install_configure_form($form, &$form_state, &$install_state) {
   drupal_add_library('system', 'drupal.timezone');
   // We add these strings as settings because JavaScript translation does not
   // work during installation.
-  drupal_add_js(array('copyFieldValue' => array('edit-site-mail' => array('edit-account-mail'))), 'setting');
+  drupal_add_js(array('copyFieldValue' => array('edit-site-mail' => array('edit-user-mail'))), 'setting');
   // Add JS to show / hide the 'Email administrator about site updates' elements
   drupal_add_js('jQuery(function () { Drupal.hideEmailAdministratorCheckbox() });', 'inline');
 
@@ -1879,7 +1879,8 @@ function _install_configure_form($form, &$form_state, &$install_state) {
   );
 
   $form['admin_account']['account']['#tree'] = TRUE;
-  $form['admin_account']['account']['name'] = array('#type' => 'textfield',
+  $form['admin_account']['account']['username'] = array(
+    '#type' => 'textfield',
     '#title' => st('Username'),
     '#maxlength' => USERNAME_MAX_LENGTH,
     '#description' => st('Spaces are allowed; punctuation is not allowed except for periods, hyphens, and underscores.'),
@@ -1893,6 +1894,7 @@ function _install_configure_form($form, &$form_state, &$install_state) {
     '#title' => st('E-mail address'),
     '#required' => TRUE,
     '#weight' => -5,
+    '#parents' => array('user', 'mail'),
   );
   $form['admin_account']['account']['pass'] = array(
     '#type' => 'password_confirm',
@@ -1960,8 +1962,8 @@ function _install_configure_form($form, &$form_state, &$install_state) {
  * @see install_configure_form_submit()
  */
 function install_configure_form_validate($form, &$form_state) {
-  if ($error = user_validate_name($form_state['values']['account']['name'])) {
-    form_error($form['admin_account']['account']['name'], $error);
+  if ($error = account_validate_name($form_state['values']['account']['username'])) {
+    form_error($form['admin_account']['account']['username'], $error);
   }
 }
 
@@ -1971,8 +1973,6 @@ function install_configure_form_validate($form, &$form_state) {
  * @see install_configure_form_validate()
  */
 function install_configure_form_submit($form, &$form_state) {
-  global $user;
-
   config('system.site')
     ->set('name', $form_state['values']['site_name'])
     ->set('mail', $form_state['values']['site_mail'])
@@ -1988,20 +1988,30 @@ function install_configure_form_submit($form, &$form_state) {
     // Add the site maintenance account's email address to the list of
     // addresses to be notified when updates are available, if selected.
     if ($form_state['values']['update_status_module'][2]) {
-      config('update.settings')->set('notification.emails', array($form_state['values']['account']['mail']))->save();
+      config('update.settings')->set('notification.emails', array($form_state['values']['user']['mail']))->save();
     }
   }
 
   // We precreated user 1 with placeholder values. Let's save the real values.
-  $account = user_load(1);
-  $account->init = $account->mail = $form_state['values']['account']['mail'];
-  $account->roles = !empty($account->roles) ? $account->roles : array();
-  $account->status = 1;
-  $account->timezone = $form_state['values']['date_default_timezone'];
-  $account->pass = $form_state['values']['account']['pass'];
-  $account->name = $form_state['values']['account']['name'];
+  $user = user_load(1);
+  $user->mail = $form_state['values']['user']['mail'];
+  $user->roles = !empty($account->roles) ? $account->roles : array();
+  $user->status = 1;
+  $user->timezone = $form_state['values']['date_default_timezone'];
+  $user->save();
+
+  $account = entity_create('account', array(
+    'uid' => $user->id(),
+    'username' => $form_state['values']['account']['username'],
+    'pass' => $form_state['values']['account']['pass'],
+    'created' => REQUEST_TIME,
+    'init' => $form_state['values']['user']['mail'],
+  ));
   $account->save();
+
   // Load global $user and perform final login tasks.
+  unset($user);
+  global $user;
   $user = user_load(1);
   user_login_finalize();
 
diff --git a/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php b/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php
index 400d885..3e6f842 100644
--- a/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php
+++ b/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php
@@ -388,27 +388,33 @@ protected function drupalCreateUser(array $permissions = array()) {
       }
     }
 
-    // Create a user assigned to that role.
-    $edit = array();
-    $edit['name']   = $this->randomName();
-    $edit['mail']   = $edit['name'] . '@example.com';
-    $edit['pass']   = user_password();
-    $edit['status'] = 1;
+    // Create a user and account assigned to that role.
+    $account_values = array();
+    $account_values['username'] = $this->randomName();
+    $account_values['pass']     = account_password();
+
+    $user_values = array();
+    $user_values['mail']   = $account_values['username'] . '@example.com';
+    $user_values['status'] = 1;
     if ($rid) {
-      $edit['roles'] = array($rid => $rid);
+      $user_values['roles'] = array($rid => $rid);
     }
+    $user = entity_create('user', $user_values);
+    $user->save();
 
-    $account = entity_create('user', $edit);
+    $account_values['uid'] = $user->uid;
+    $account = entity_create('account', $account_values);
     $account->save();
 
-    $this->assertTrue(!empty($account->uid), t('User created with name %name and pass %pass', array('%name' => $edit['name'], '%pass' => $edit['pass'])), t('User login'));
+    $this->assertTrue(!empty($account->uid), t('User created with name %username and pass %pass', array('%username' => $account_values['username'], '%pass' => $account_values['pass'])), t('User login'));
     if (empty($account->uid)) {
       return FALSE;
     }
 
     // Add the raw password so that we can log in as this user.
-    $account->pass_raw = $edit['pass'];
-    return $account;
+    $user->username = $account_values['username'];
+    $user->pass_raw = $account_values['pass'];
+    return $user;
   }
 
   /**
@@ -531,14 +537,14 @@ protected function drupalLogin($user) {
     }
 
     $edit = array(
-      'name' => $user->name,
+      'username' => $user->username,
       'pass' => $user->pass_raw
     );
     $this->drupalPost('user', $edit, t('Log in'));
 
     // If a "log out" link appears on the page, it is almost certainly because
     // the login was successful.
-    $pass = $this->assertLink(t('Log out'), 0, t('User %name successfully logged in.', array('%name' => $user->name)), t('User login'));
+    $pass = $this->assertLink(t('Log out'), 0, t('User %username successfully logged in.', array('%username' => $user->username)), t('User login'));
 
     if ($pass) {
       $this->loggedInUser = $user;
@@ -562,7 +568,7 @@ protected function drupalLogout() {
     // screen.
     $this->drupalGet('user/logout', array('query' => array('destination' => 'user')));
     $this->assertResponse(200, t('User was logged out.'));
-    $pass = $this->assertField('name', t('Username field found.'), t('Logout'));
+    $pass = $this->assertField('username', t('Username field found.'), t('Logout'));
     $pass = $pass && $this->assertField('pass', t('Password field found.'), t('Logout'));
 
     if ($pass) {
@@ -656,13 +662,15 @@ protected function setUp() {
           'site_name' => 'Drupal',
           'site_mail' => 'simpletest@example.com',
           'account' => array(
-            'name' => $this->root_user->name,
-            'mail' => $this->root_user->mail,
+            'username' => $this->root_user->name,
             'pass' => array(
               'pass1' => $this->root_user->pass_raw,
               'pass2' => $this->root_user->pass_raw,
             ),
           ),
+          'user' => array(
+            'mail' => $this->root_user->mail,
+          ),
           // form_type_checkboxes_value() requires NULL instead of FALSE values
           // for programmatic form submissions to disable a checkbox.
           'update_status_module' => array(
diff --git a/core/modules/user/lib/Drupal/user/Account.php b/core/modules/user/lib/Drupal/user/Account.php
new file mode 100644
index 0000000..910864c
--- /dev/null
+++ b/core/modules/user/lib/Drupal/user/Account.php
@@ -0,0 +1,72 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\user\Account.
+ */
+
+namespace Drupal\user;
+
+use Drupal\Core\Entity\Entity;
+
+/**
+ * Defines the account entity class;
+ */
+class Account extends Entity {
+
+  /**
+   * The account ID.
+   *
+   * @var integer
+   */
+  public $aid;
+
+  /**
+   * The user ID for this account.
+   *
+   * @var integer
+   */
+  public $uid;
+
+  /**
+   * The unique username for this account.
+   *
+   * @var string
+   */
+  public $username;
+
+  /**
+   * The account password (hashed).
+   *
+   * @var string
+   */
+  public $pass;
+
+  /**
+   * The timestamp when the account was created.
+   *
+   * @var integer
+   */
+  public $created;
+
+  /**
+   * Whether the user is active (1) or blocked (0).
+   *
+   * @var integer
+   */
+  public $status = 1;
+
+  /**
+   * The email address used for initial account creation.
+   *
+   * @var string
+   */
+  public $init = '';
+
+  /**
+   * Implements Drupal\Core\Entity\EntityInterface::id().
+   */
+  public function id() {
+    return $this->aid;
+  }
+}
\ No newline at end of file
diff --git a/core/modules/user/lib/Drupal/user/AccountFormController.php b/core/modules/user/lib/Drupal/user/AccountFormController.php
index b79e983..547eb80 100644
--- a/core/modules/user/lib/Drupal/user/AccountFormController.php
+++ b/core/modules/user/lib/Drupal/user/AccountFormController.php
@@ -32,31 +32,19 @@ public function form(array $form, array &$form_state, EntityInterface $account)
       '#weight' => -10,
     );
 
-    // Only show name field on registration form or user can change own username.
-    $form['account']['name'] = array(
+    // Only show username field on registration form or user can change own username.
+    $form['account']['username'] = array(
       '#type' => 'textfield',
       '#title' => t('Username'),
       '#maxlength' => USERNAME_MAX_LENGTH,
       '#description' => t('Spaces are allowed; punctuation is not allowed except for periods, hyphens, apostrophes, and underscores.'),
       '#required' => TRUE,
       '#attributes' => array('class' => array('username'), 'autocomplete' => 'off'),
-      '#default_value' => (!$register ? $account->name : ''),
+      '#default_value' => (!$register ? $account->username : ''),
       '#access' => ($register || ($user->uid == $account->uid && user_access('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' => t('E-mail address'),
-      '#description' => 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' => !(empty($account->mail) && user_access('administer users')),
-      '#default_value' => (!$register ? $account->mail : ''),
-      '#attributes' => array('autocomplete' => 'off'),
-    );
-
     // Display password field only for existing users or when user is allowed to
     // assign a password during registration.
     if (!$register) {
@@ -75,10 +63,9 @@ public function form(array $form, array &$form_state, EntityInterface $account)
       // 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['pass'] = t('Password');
         $request_new = l(t('Request new password'), 'user/password', array('attributes' => array('title' => t('Request new password via e-mail.'))));
-        $current_pass_description = 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));
+        $current_pass_description = t('Required if you want to change the  %pass below. !request_new.', array('%pass' => $protected_values['pass'], '!request_new' => $request_new));
       }
 
       // The user must enter their current password to change to a new one.
@@ -118,205 +105,43 @@ public function form(array $form, array &$form_state, EntityInterface $account)
       $status = $register ? $config->get('register') == USER_REGISTER_VISITORS : $account->status;
     }
 
-    $form['account']['status'] = array(
-      '#type' => 'radios',
-      '#title' => t('Status'),
-      '#default_value' => $status,
-      '#options' => array(t('Blocked'), t('Active')),
-      '#access' => $admin,
-    );
-
-    $roles = array_map('check_plain', user_roles(TRUE));
-    // The disabled checkbox subelement for the 'authenticated user' role
-    // must be generated separately and added to the checkboxes element,
-    // because of a limitation in Form API not supporting a single disabled
-    // checkbox within a set of checkboxes.
-    // @todo This should be solved more elegantly. See issue #119038.
-    $checkbox_authenticated = array(
-      '#type' => 'checkbox',
-      '#title' => $roles[DRUPAL_AUTHENTICATED_RID],
-      '#default_value' => TRUE,
-      '#disabled' => TRUE,
-    );
-    unset($roles[DRUPAL_AUTHENTICATED_RID]);
-
-    $form['account']['roles'] = array(
-      '#type' => 'checkboxes',
-      '#title' => t('Roles'),
-      '#default_value' => (!$register && isset($account->roles) ? array_keys($account->roles) : array()),
-      '#options' => $roles,
-      '#access' => $roles && user_access('administer permissions'),
-      DRUPAL_AUTHENTICATED_RID => $checkbox_authenticated,
-    );
-
     $form['account']['notify'] = array(
       '#type' => 'checkbox',
       '#title' => t('Notify user of new account'),
       '#access' => $register && $admin,
     );
 
-    // Signature.
-    $form['signature_settings'] = array(
-      '#type' => 'fieldset',
-      '#title' => t('Signature settings'),
-      '#weight' => 1,
-      '#access' => (!$register && $config->get('signatures')),
-    );
-
-    $form['signature_settings']['signature'] = array(
-      '#type' => 'text_format',
-      '#title' => t('Signature'),
-      '#default_value' => isset($account->signature) ? $account->signature : '',
-      '#description' => t('Your signature will be publicly displayed at the end of your comments.'),
-      '#format' => isset($account->signature_format) ? $account->signature_format : NULL,
-    );
-
-    // Picture/avatar.
-    $form['picture'] = array(
-      '#type' => 'fieldset',
-      '#title' => t('Picture'),
-      '#weight' => 1,
-      '#access' => (!$register && variable_get('user_pictures', 0)),
-    );
-
-    $form['picture']['picture'] = array(
-      '#type' => 'value',
-      '#value' => isset($account->picture) ? $account->picture : NULL,
-    );
-
-    $form['picture']['picture_current'] = array(
-      '#markup' => theme('user_picture', array('account' => $account)),
-    );
-
-    $form['picture']['picture_delete'] = array(
-      '#type' => 'checkbox',
-      '#title' => t('Delete picture'),
-      '#access' => !empty($account->picture->fid),
-      '#description' => t('Check this box to delete your current picture.'),
-    );
-
-    $form['picture']['picture_upload'] = array(
-      '#type' => 'file',
-      '#title' => t('Upload picture'),
-      '#size' => 48,
-      '#description' => t('Your virtual face or picture. Pictures larger than @dimensions pixels will be scaled down.', array('@dimensions' => variable_get('user_picture_dimensions', '85x85'))) . ' ' . filter_xss_admin(variable_get('user_picture_guidelines', '')),
-    );
-
-    $form['#validate'][] = 'user_validate_picture';
-
-    $user_preferred_langcode = $register ? $language_interface->langcode : user_preferred_langcode($account);
-
-    $user_preferred_admin_langcode = $register ? $language_interface->langcode : user_preferred_langcode($account, 'admin');
-
-    // Is default the interface language?
-    include_once DRUPAL_ROOT . '/core/includes/language.inc';
-    $interface_language_is_default = language_negotiation_method_get_first(LANGUAGE_TYPE_INTERFACE) != LANGUAGE_NEGOTIATION_SELECTED;
-    $form['language'] = array(
-      '#type' => language_multilingual() ? 'fieldset' : 'container',
-      '#title' => t('Language settings'),
-      // Display language selector when either creating a user on the admin
-      // interface or editing a user account.
-      '#access' => !$register || user_access('administer users'),
-    );
-
-    $form['language']['preferred_langcode'] = array(
-      '#type' => 'language_select',
-      '#title' => t('Site language'),
-      '#languages' => LANGUAGE_CONFIGURABLE,
-      '#default_value' => $user_preferred_langcode,
-      '#description' => $interface_language_is_default ? t("This account's preferred language for e-mails and site presentation.") : t("This account's preferred language for e-mails."),
-    );
-
-    $form['language']['preferred_admin_langcode'] = array(
-      '#type' => 'language_select',
-      '#title' => t('Administration pages language'),
-      '#languages' => LANGUAGE_CONFIGURABLE,
-      '#default_value' => $user_preferred_admin_langcode,
-      '#access' => user_access('access administration pages', $account),
-    );
-
-    // User entities contain both a langcode property (for identifying the
-    // language of the entity data) and a preferred_langcode property (see
-    // above). Rather than provide a UI forcing the user to choose both
-    // separately, assume that the user profile data is in the user's preferred
-    // language. This element provides that synchronization. For use-cases where
-    // this synchronization is not desired, a module can alter or remove this
-    // element.
-    $form['language']['langcode'] = array(
-      '#type' => 'value',
-      '#value_callback' => '_user_language_selector_langcode_value',
-      // For the synchronization to work, this element must have a larger weight
-      // than the preferred_langcode element. Set a large weight here in case
-      // a module alters the weight of the other element.
-      '#weight' => 100,
-    );
-
     return parent::form($form, $form_state, $account);
   }
 
   /**
-   * Overrides Drupal\Core\Entity\EntityFormController::submit().
+   * Overrides Drupal\Core\Entity\EntityFormController::validate().
    */
   public function validate(array $form, array &$form_state) {
     parent::validate($form, $form_state);
 
     $account = $this->getEntity($form_state);
     // Validate new or changing username.
-    if (isset($form_state['values']['name'])) {
-      if ($error = user_validate_name($form_state['values']['name'])) {
-        form_set_error('name', $error);
+    if (isset($form_state['values']['username'])) {
+      if ($error = account_validate_name($form_state['values']['username'])) {
+        form_set_error('username', $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) db_select('users')
-        ->fields('users', array('uid'))
+        $name_taken = (bool) db_select('account')
+        ->fields('account', array('uid'))
         ->condition('uid', (int) $account->uid, '<>')
-        ->condition('name', db_like($form_state['values']['name']), 'LIKE')
+        ->condition('username', db_like($form_state['values']['username']), 'LIKE')
         ->range(0, 1)
         ->execute()
         ->fetchField();
 
         if ($name_taken) {
-          form_set_error('name', t('The name %name is already taken.', array('%name' => $form_state['values']['name'])));
+          form_set_error('username', t('The username %username is already taken.', array('%username' => $form_state['values']['username'])));
         }
       }
     }
-
-    $mail = $form_state['values']['mail'];
-
-    if (!empty($mail)) {
-      $mail_taken = (bool) db_select('users')
-      ->fields('users', array('uid'))
-      ->condition('uid', (int) $account->uid, '<>')
-      ->condition('mail', db_like($mail), 'LIKE')
-      ->range(0, 1)
-      ->execute()
-      ->fetchField();
-
-      if ($mail_taken) {
-        // Format error message dependent on whether the user is logged in or not.
-        if ($GLOBALS['user']->uid) {
-          form_set_error('mail', t('The e-mail address %email is already taken.', array('%email' => $mail)));
-        }
-        else {
-          form_set_error('mail', 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'])) {
-      // Move text format for user signature into 'signature_format'.
-      $form_state['values']['signature_format'] = $form_state['values']['signature']['format'];
-      // Move text value for user signature into 'signature'.
-      $form_state['values']['signature'] = $form_state['values']['signature']['value'];
-
-      $user_schema = drupal_get_schema('users');
-      if (drupal_strlen($form_state['values']['signature']) > $user_schema['fields']['signature']['length']) {
-        form_set_error('signature', t('The signature is too long: it must be %max characters or less.', array('%max' => $user_schema['fields']['signature']['length'])));
-      }
-    }
   }
+
 }
diff --git a/core/modules/user/lib/Drupal/user/AccountStorageController.php b/core/modules/user/lib/Drupal/user/AccountStorageController.php
new file mode 100644
index 0000000..86f797b
--- /dev/null
+++ b/core/modules/user/lib/Drupal/user/AccountStorageController.php
@@ -0,0 +1,86 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\user\AccountStorageController.
+ */
+
+namespace Drupal\user;
+
+use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Entity\EntityMalformedException;
+use Drupal\Core\Entity\DatabaseStorageController;
+
+/**
+ * Controller class for accounts.
+ *
+ * This extends the Drupal\Core\Entity\DatabaseStorageController class, adding
+ * required special handling for user objects.
+ */
+class AccountStorageController extends DatabaseStorageController {
+
+  /**
+   * Overrides Drupal\Core\Entity\DatabaseStorageController::preSave().
+   */
+  protected function preSave(EntityInterface $entity) {
+    // Update the user password if it has changed.
+    if ($entity->isNew() || (!empty($entity->pass) && $entity->pass != $entity->original->pass)) {
+      // Allow alternate password hashing schemes.
+      require_once DRUPAL_ROOT . '/' . variable_get('password_inc', 'core/includes/password.inc');
+      $entity->pass = user_hash_password(trim($entity->pass));
+      // Abort if the hashing failed and returned FALSE.
+      if (!$entity->pass) {
+        throw new EntityMalformedException('The entity does not have a password.');
+      }
+    }
+
+    if (!$entity->isNew()) {
+      // If the password is empty, that means it was not changed, so use the
+      // original password.
+      if (empty($entity->pass)) {
+        $entity->pass = $entity->original->pass;
+      }
+    }
+
+    if (empty($entity->uid)) {
+      // Create a User for this Account.
+      $user = entity_create('user', array(
+        'mail' => $entity->init,
+        'created' => REQUEST_TIME,
+        'status' => 1,
+      ));
+      $user->save();
+      $entity->uid = $user->uid;
+    }
+  }
+
+  /**
+   * Overrides Drupal\Core\Entity\DatabaseStorageController::postSave().
+   */
+  protected function postSave(EntityInterface $entity, $update) {
+    if ($update) {
+      // If the username was changed and the user entity nice name was set as
+      // the username, update it.
+      if ($entity->original->username != $entity->username &&
+          $entity->original->username == $user->name) {
+        $user = entity_load('user', $entity->uid);
+        $user->name = $entity->username;
+        $user->save();
+      }
+
+      // If the password has been changed, delete all open sessions for the
+      // user and recreate the current one.
+      if ($entity->pass != $entity->original->pass) {
+        drupal_session_destroy_uid($entity->uid);
+        if ($entity->uid == $GLOBALS['user']->uid) {
+          drupal_session_regenerate();
+        }
+      }
+    }
+    else {
+      $user = entity_load('user', $entity->uid);
+      $user->name = $entity->username;
+      $user->save();
+    }
+  }
+}
diff --git a/core/modules/user/lib/Drupal/user/RegisterFormController.php b/core/modules/user/lib/Drupal/user/RegisterFormController.php
index 6e4a260..4cd8b74 100644
--- a/core/modules/user/lib/Drupal/user/RegisterFormController.php
+++ b/core/modules/user/lib/Drupal/user/RegisterFormController.php
@@ -20,6 +20,8 @@ class RegisterFormController extends AccountFormController {
   public function form(array $form, array &$form_state, EntityInterface $account) {
     global $user;
 
+    $language_interface = language(LANGUAGE_TYPE_INTERFACE);
+    $register = empty($account->uid);
     $admin = user_access('administer users');
 
     // Pass access information to the submit handler. Running an access check
@@ -41,6 +43,15 @@ public function form(array $form, array &$form_state, EntityInterface $account)
     // Start with the default user account fields.
     $form = parent::form($form, $form_state, $account);
 
+    $form['account']['init'] = array(
+      '#type' => 'email',
+      '#title' => t('E-mail address'),
+      '#description' => 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' => !(empty($account->init) && user_access('administer users')),
+      '#default_value' => (!$register ? $account->init : ''),
+      '#attributes' => array('autocomplete' => 'off'),
+    );
+
     // Attach field widgets, and hide the ones where the 'user_register_form'
     // setting is not on.
     field_attach_form('user', $account, $form, $form_state);
@@ -78,14 +89,13 @@ public function submit(array $form, array &$form_state) {
       $pass = $form_state['values']['pass'];
     }
     else {
-      $pass = user_password();
+      $pass = account_password();
     }
 
     // Remove unneeded values.
     form_state_values_clean($form_state);
 
     $form_state['values']['pass'] = $pass;
-    $form_state['values']['init'] = $form_state['values']['mail'];
 
     parent::submit($form, $form_state);
   }
@@ -101,6 +111,10 @@ public function save(array $form, array &$form_state) {
 
     $account->save();
 
+    // Get our user entity and store our pass against it.
+    $user = user_load($account->uid);
+    $user->pass = $account->pass;
+
     // Terminate if an error occurred while saving the account.
     if ($status =! SAVED_NEW) {
       drupal_set_message(t("Error saving user account."), 'error');
@@ -110,7 +124,7 @@ public function save(array $form, array &$form_state) {
     $form_state['user'] = $account;
     $form_state['values']['uid'] = $account->uid;
 
-    watchdog('user', 'New user: %name (%email).', array('%name' => $form_state['values']['name'], '%email' => $form_state['values']['mail']), WATCHDOG_NOTICE, l(t('edit'), 'user/' . $account->uid . '/edit'));
+    watchdog('user', 'New user: %username (%email).', array('%name' => $form_state['values']['username'], '%email' => $form_state['values']['init']), WATCHDOG_NOTICE, l(t('edit'), 'user/' . $account->uid . '/edit'));
 
     // Add plain text password into user account to generate mail tokens.
     $account->password = $pass;
@@ -118,11 +132,11 @@ public function save(array $form, array &$form_state) {
     // New administrative account without notification.
     $uri = $account->uri();
     if ($admin && !$notify) {
-      drupal_set_message(t('Created a new user account for <a href="@url">%name</a>. No e-mail has been sent.', array('@url' => url($uri['path'], $uri['options']), '%name' => $account->name)));
+      drupal_set_message(t('Created a new user account for <a href="@url">%username</a>. No e-mail has been sent.', array('@url' => url($uri['path'], $uri['options']), '%username' => $account->username)));
     }
     // No e-mail verification required; log in user immediately.
     elseif (!$admin && !config('user.settings')->get('verify_mail') && $account->status) {
-      _user_mail_notify('register_no_approval_required', $account);
+      _user_mail_notify('register_no_approval_required', $user);
       $form_state['uid'] = $account->uid;
       user_login_submit(array(), $form_state);
       drupal_set_message(t('Registration successful. You are now logged in.'));
@@ -130,14 +144,14 @@ public function save(array $form, array &$form_state) {
     }
     // No administrator approval required.
     elseif ($account->status || $notify) {
-      if (empty($account->mail) && $notify) {
-        drupal_set_message(t('The new user <a href="@url">%name</a> was created without an email address, so no welcome message was sent.', array('@url' => url($uri['path'], $uri['options']), '%name' => $account->name)));
+      if (empty($account->init) && $notify) {
+        drupal_set_message(t('The new user <a href="@url">%username</a> was created without an email address, so no welcome message was sent.', array('@url' => url($uri['path'], $uri['options']), '%username' => $account->username)));
       }
       else {
         $op = $notify ? 'register_admin_created' : 'register_no_approval_required';
-        _user_mail_notify($op, $account);
+        _user_mail_notify($op, $user);
         if ($notify) {
-          drupal_set_message(t('A welcome message with further instructions has been e-mailed to the new user <a href="@url">%name</a>.', array('@url' => url($uri['path'], $uri['options']), '%name' => $account->name)));
+          drupal_set_message(t('A welcome message with further instructions has been e-mailed to the new user <a href="@url">%username</a>.', array('@url' => url($uri['path'], $uri['options']), '%username' => $account->username)));
         }
         else {
           drupal_set_message(t('A welcome message with further instructions has been sent to your e-mail address.'));
@@ -147,7 +161,7 @@ public function save(array $form, array &$form_state) {
     }
     // Administrator approval required.
     else {
-      _user_mail_notify('register_pending_approval', $account);
+      _user_mail_notify('register_pending_approval', $user);
       drupal_set_message(t('Thank you for applying for an account. Your account is currently pending approval by the site administrator.<br />In the meantime, a welcome message with further instructions has been sent to your e-mail address.'));
       $form_state['redirect'] = '';
     }
diff --git a/core/modules/user/lib/Drupal/user/SettingsFormController.php b/core/modules/user/lib/Drupal/user/SettingsFormController.php
new file mode 100644
index 0000000..c65d5c4
--- /dev/null
+++ b/core/modules/user/lib/Drupal/user/SettingsFormController.php
@@ -0,0 +1,62 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\user\SettingsFormController.
+ */
+
+namespace Drupal\user;
+
+use Drupal\Core\Entity\EntityInterface;
+
+/**
+ * Form controller for the profile forms.
+ */
+class SettingsFormController extends UserFormController {
+
+  /**
+   * Overrides Drupal\Core\Entity\EntityFormController::actions().
+   */
+  protected function actions(array $form, array &$form_state) {
+    $element = parent::actions($form, $form_state);
+    $account = $this->getEntity($form_state);
+
+    // @todo Actually the cancel action can be assimilated to the delete one: we
+    // should alter it instead of providing a new one.
+    unset($element['delete']);
+
+    $element['cancel'] = array(
+      '#type' => 'submit',
+      '#value' => t('Cancel account'),
+      '#submit' => array('user_edit_cancel_submit'),
+      '#access' => $account->uid > 1 && (($account->uid == $GLOBALS['user']->uid && user_access('cancel account')) || user_access('administer users')),
+    );
+
+    return $element;
+  }
+
+  /**
+   * Overrides Drupal\Core\Entity\EntityFormController::submit().
+   */
+  public function submit(array $form, array &$form_state) {
+    // @todo Consider moving this into the parent method.
+    // Remove unneeded values.
+    form_state_values_clean($form_state);
+    parent::submit($form, $form_state);
+  }
+
+  /**
+   * Overrides Drupal\Core\Entity\EntityFormController::save().
+   */
+  public function save(array $form, array &$form_state) {
+    $account = $this->getEntity($form_state);
+    $account->save();
+    $form_state['values']['uid'] = $account->id();
+
+    // Clear the page cache because pages can contain usernames and/or profile
+    // information:
+    cache_invalidate(array('content' => TRUE));
+
+    drupal_set_message(t('The changes have been saved.'));
+  }
+}
diff --git a/core/modules/user/lib/Drupal/user/User.php b/core/modules/user/lib/Drupal/user/User.php
index 2217588..63178ba 100644
--- a/core/modules/user/lib/Drupal/user/User.php
+++ b/core/modules/user/lib/Drupal/user/User.php
@@ -36,13 +36,6 @@ class User extends Entity {
   public $name = '';
 
   /**
-   * The user's password (hashed).
-   *
-   * @var string
-   */
-  public $pass;
-
-  /**
    * The user's email address.
    *
    * @var string
@@ -136,13 +129,6 @@ class User extends Entity {
   public $picture = 0;
 
   /**
-   * The email address used for initial account creation.
-   *
-   * @var string
-   */
-  public $init = '';
-
-  /**
    * The user's roles.
    *
    * @var array
@@ -151,8 +137,15 @@ class User extends Entity {
 
   /**
    * Implements Drupal\Core\Entity\EntityInterface::id().
+   *
+   * To help other systems integrate with the anonymous user API we will save
+   * the user as soon as an ID is requested for it so we can keep track of it.
    */
   public function id() {
+    if (!empty($this->enforceIsNew) || !$this->uid) {
+      $this->save();
+    }
+
     return $this->uid;
   }
 }
diff --git a/core/modules/user/lib/Drupal/user/UserFormController.php b/core/modules/user/lib/Drupal/user/UserFormController.php
new file mode 100644
index 0000000..6b250f3
--- /dev/null
+++ b/core/modules/user/lib/Drupal/user/UserFormController.php
@@ -0,0 +1,240 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\user\UserFormController.
+ */
+
+namespace Drupal\user;
+
+use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Entity\EntityFormController;
+
+/**
+ * Form controller for the user account forms.
+ */
+abstract class UserFormController extends EntityFormController {
+
+  /**
+   * Overrides Drupal\Core\Entity\EntityFormController::form().
+   */
+  public function form(array $form, array &$form_state, EntityInterface $account) {
+    global $user;
+    $config = config('user.settings');
+
+    $language_interface = language(LANGUAGE_TYPE_INTERFACE);
+    $register = empty($account->uid);
+    $admin = user_access('administer users');
+
+    // User information.
+    $form['user'] = array(
+      '#type'   => 'container',
+      '#weight' => -10,
+    );
+
+    if ($admin) {
+      $status = isset($account->status) ? $account->status : 1;
+    }
+    else {
+      $status = $register ? $config->get('register') == USER_REGISTER_VISITORS : $account->status;
+    }
+
+    // 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.
+    // We need to retrieve the user and store the mail against the account for
+    // the protected values validation to work.
+    $form['user']['mail'] = array(
+      '#type' => 'email',
+      '#title' => t('E-mail address'),
+      '#description' => 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' => !(empty($account->mail) && user_access('administer users')),
+      '#default_value' => (!$register ? $account->mail : ''),
+      '#attributes' => array('autocomplete' => 'off'),
+    );
+
+    // Display password field only for existing users or when user is allowed to
+    // assign a password during registration.
+    if (!$register && $account_account = account_uid_load($account->uid)) {
+      $protected_values = array();
+      $current_pass_description = '';
+
+      // The user may only change their own password without their current
+      // password if they logged in via a one-time login link.
+      $protected_values['mail'] = $form['user']['mail']['#title'];
+      $current_pass_description = t('Required if you want to change the %mail below..', array('%mail' => $protected_values['mail']));
+
+      // The user must enter their current password to change to a new one.
+      if ($user->uid == $account->uid) {
+        $form['user']['current_pass_required_values'] = array(
+          '#type' => 'value',
+          '#value' => $protected_values,
+        );
+
+        $form['user']['current_pass'] = array(
+          '#type' => 'password',
+          '#title' => t('Current password'),
+          '#size' => 25,
+          '#access' => !empty($protected_values),
+          '#description' => $current_pass_description,
+          '#weight' => -5,
+          '#attributes' => array('autocomplete' => 'off'),
+        );
+
+        $account->pass = $account_account->pass;
+        $form_state['user'] = $account;
+        $form['#validate'][] = 'user_validate_current_pass';
+      }
+    }
+
+    $form['user']['status'] = array(
+      '#type' => 'radios',
+      '#title' => t('Status'),
+      '#default_value' => $status,
+      '#options' => array(t('Blocked'), t('Active')),
+      '#access' => $admin,
+    );
+
+    $roles = array_map('check_plain', user_roles(TRUE));
+    // The disabled checkbox subelement for the 'authenticated user' role
+    // must be generated separately and added to the checkboxes element,
+    // because of a limitation in Form API not supporting a single disabled
+    // checkbox within a set of checkboxes.
+    // @todo This should be solved more elegantly. See issue #119038.
+    $checkbox_authenticated = array(
+      '#type' => 'checkbox',
+      '#title' => $roles[DRUPAL_AUTHENTICATED_RID],
+      '#default_value' => TRUE,
+      '#disabled' => TRUE,
+    );
+    unset($roles[DRUPAL_AUTHENTICATED_RID]);
+
+    $form['user']['roles'] = array(
+      '#type' => 'checkboxes',
+      '#title' => t('Roles'),
+      '#default_value' => (!$register && isset($account->roles) ? array_keys($account->roles) : array()),
+      '#options' => $roles,
+      '#access' => $roles && user_access('administer permissions'),
+      DRUPAL_AUTHENTICATED_RID => $checkbox_authenticated,
+    );
+
+    // Signature.
+    $form['signature_settings'] = array(
+      '#type' => 'fieldset',
+      '#title' => t('Signature settings'),
+      '#weight' => 1,
+      '#access' => (!$register && $config->get('signatures')),
+    );
+
+    $form['signature_settings']['signature'] = array(
+      '#type' => 'text_format',
+      '#title' => t('Signature'),
+      '#default_value' => isset($account->signature) ? $account->signature : '',
+      '#description' => t('Your signature will be publicly displayed at the end of your comments.'),
+      '#format' => isset($account->signature_format) ? $account->signature_format : NULL,
+    );
+
+    // Picture/avatar.
+    $form['picture'] = array(
+      '#type' => 'fieldset',
+      '#title' => t('Picture'),
+      '#weight' => 1,
+      '#access' => (!$register && variable_get('user_pictures', 0)),
+    );
+
+    $form['picture']['picture'] = array(
+      '#type' => 'value',
+      '#value' => isset($account->picture) ? $account->picture : NULL,
+    );
+
+    $form['picture']['picture_current'] = array(
+      '#markup' => theme('user_picture', array('account' => $account)),
+    );
+
+    $form['picture']['picture_delete'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('Delete picture'),
+      '#access' => !empty($account->picture->fid),
+      '#description' => t('Check this box to delete your current picture.'),
+    );
+
+    $form['picture']['picture_upload'] = array(
+      '#type' => 'file',
+      '#title' => t('Upload picture'),
+      '#size' => 48,
+      '#description' => t('Your virtual face or picture. Pictures larger than @dimensions pixels will be scaled down.', array('@dimensions' => variable_get('user_picture_dimensions', '85x85'))) . ' ' . filter_xss_admin(variable_get('user_picture_guidelines', '')),
+    );
+
+    $form['#validate'][] = 'user_validate_picture';
+
+    $user_preferred_langcode = $register ? $language_interface->langcode : user_preferred_langcode($account);
+
+    $user_preferred_admin_langcode = $register ? $language_interface->langcode : user_preferred_langcode($account, 'admin');
+
+    // Is default the interface language?
+    include_once DRUPAL_ROOT . '/core/includes/language.inc';
+    $interface_language_is_default = language_negotiation_method_get_first(LANGUAGE_TYPE_INTERFACE) != LANGUAGE_NEGOTIATION_SELECTED;
+    $form['language'] = array(
+      '#type' => language_multilingual() ? 'fieldset' : 'container',
+      '#title' => t('Language settings'),
+      // Display language selector when either creating a user on the admin
+      // interface or editing a user account.
+      '#access' => !$register || user_access('administer users'),
+    );
+
+    $form['language']['preferred_langcode'] = array(
+      '#type' => 'language_select',
+      '#title' => t('Site language'),
+      '#languages' => LANGUAGE_CONFIGURABLE,
+      '#default_value' => $user_preferred_langcode,
+      '#description' => $interface_language_is_default ? t("This account's preferred language for e-mails and site presentation.") : t("This account's preferred language for e-mails."),
+    );
+
+    $form['language']['preferred_admin_langcode'] = array(
+      '#type' => 'language_select',
+      '#title' => t('Administration pages language'),
+      '#languages' => LANGUAGE_CONFIGURABLE,
+      '#default_value' => $user_preferred_admin_langcode,
+      '#access' => user_access('access administration pages', $account),
+    );
+
+    // User entities contain both a langcode property (for identifying the
+    // language of the entity data) and a preferred_langcode property (see
+    // above). Rather than provide a UI forcing the user to choose both
+    // separately, assume that the user profile data is in the user's preferred
+    // language. This element provides that synchronization. For use-cases where
+    // this synchronization is not desired, a module can alter or remove this
+    // element.
+    $form['language']['langcode'] = array(
+      '#type' => 'value',
+      '#value_callback' => '_user_language_selector_langcode_value',
+      // For the synchronization to work, this element must have a larger weight
+      // than the preferred_langcode element. Set a large weight here in case
+      // a module alters the weight of the other element.
+      '#weight' => 100,
+    );
+
+    return parent::form($form, $form_state, $account);
+  }
+
+  /**
+   * Overrides Drupal\Core\Entity\EntityFormController::submit().
+   */
+  public function validate(array $form, array &$form_state) {
+    parent::validate($form, $form_state);
+
+    // 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'])) {
+      // Move text format for user signature into 'signature_format'.
+      $form_state['values']['signature_format'] = $form_state['values']['signature']['format'];
+      // Move text value for user signature into 'signature'.
+      $form_state['values']['signature'] = $form_state['values']['signature']['value'];
+
+      $user_schema = drupal_get_schema('users');
+      if (drupal_strlen($form_state['values']['signature']) > $user_schema['fields']['signature']['length']) {
+        form_set_error('signature', t('The signature is too long: it must be %max characters or less.', array('%max' => $user_schema['fields']['signature']['length'])));
+      }
+    }
+  }
+}
diff --git a/core/modules/user/lib/Drupal/user/UserStorageController.php b/core/modules/user/lib/Drupal/user/UserStorageController.php
index 2660300..b71c009 100644
--- a/core/modules/user/lib/Drupal/user/UserStorageController.php
+++ b/core/modules/user/lib/Drupal/user/UserStorageController.php
@@ -87,16 +87,6 @@ public function save(EntityInterface $entity) {
    * Overrides Drupal\Core\Entity\DatabaseStorageController::preSave().
    */
   protected function preSave(EntityInterface $entity) {
-    // Update the user password if it has changed.
-    if ($entity->isNew() || (!empty($entity->pass) && $entity->pass != $entity->original->pass)) {
-      // Allow alternate password hashing schemes.
-      require_once DRUPAL_ROOT . '/' . variable_get('password_inc', 'core/includes/password.inc');
-      $entity->pass = user_hash_password(trim($entity->pass));
-      // Abort if the hashing failed and returned FALSE.
-      if (!$entity->pass) {
-        throw new EntityMalformedException('The entity does not have a password.');
-      }
-    }
 
     if (!empty($entity->picture_upload)) {
       $entity->picture = $entity->picture_upload;
@@ -136,12 +126,6 @@ protected function preSave(EntityInterface $entity) {
         }
       }
       $entity->picture = empty($entity->picture->fid) ? 0 : $entity->picture->fid;
-
-      // If the password is empty, that means it was not changed, so use the
-      // original password.
-      if (empty($entity->pass)) {
-        $entity->pass = $entity->original->pass;
-      }
     }
 
     // Prepare user roles.
@@ -163,15 +147,6 @@ protected function preSave(EntityInterface $entity) {
   protected function postSave(EntityInterface $entity, $update) {
 
     if ($update) {
-      // If the password has been changed, delete all open sessions for the
-      // user and recreate the current one.
-      if ($entity->pass != $entity->original->pass) {
-        drupal_session_destroy_uid($entity->uid);
-        if ($entity->uid == $GLOBALS['user']->uid) {
-          drupal_session_regenerate();
-        }
-      }
-
       // Remove roles that are no longer enabled for the user.
       $entity->roles = array_filter($entity->roles);
 
@@ -232,5 +207,8 @@ protected function postDelete($entities) {
     db_delete('authmap')
       ->condition('uid', array_keys($entities), 'IN')
       ->execute();
+    db_delete('account')
+      ->condition('uid', array_keys($entities), 'IN')
+      ->execute();
   }
 }
diff --git a/core/modules/user/user.admin.inc b/core/modules/user/user.admin.inc
index 396f4c0..8c217cc 100644
--- a/core/modules/user/user.admin.inc
+++ b/core/modules/user/user.admin.inc
@@ -11,7 +11,7 @@ function user_admin($callback_arg = '') {
   switch ($op) {
     case t('Create new account'):
     case 'create':
-      $account = entity_create('user', array());
+      $account = entity_create('account', array());
       $build['user_register'] = entity_get_form($account, 'register');
       break;
     default:
diff --git a/core/modules/user/user.install b/core/modules/user/user.install
index a099f6b..26707be 100644
--- a/core/modules/user/user.install
+++ b/core/modules/user/user.install
@@ -18,8 +18,8 @@ function user_schema() {
         'type' => 'int',
         'unsigned' => TRUE,
         'not null' => TRUE,
-        'description' => 'Primary Key: Unique user ID.',
         'default' => 0,
+        'description' => 'Primary Key: Unique user ID.',
       ),
       'uuid' => array(
         'description' => 'Unique Key: Universally unique identifier for this entity.',
@@ -32,7 +32,7 @@ function user_schema() {
         'length' => 60,
         'not null' => TRUE,
         'default' => '',
-        'description' => 'Unique user name.',
+        'description' => 'Nice name for the user.',
       ),
       'langcode' => array(
         'type' => 'varchar',
@@ -41,13 +41,6 @@ function user_schema() {
         'default' => '',
         'description' => "The {language}.langcode of the user's profile.",
       ),
-      'pass' => array(
-        'type' => 'varchar',
-        'length' => 128,
-        'not null' => TRUE,
-        'default' => '',
-        'description' => "User's password (hashed).",
-      ),
       'mail' => array(
         'type' => 'varchar',
         'length' => 254,
@@ -126,13 +119,6 @@ function user_schema() {
         'default' => 0,
         'description' => "Foreign key: {file_managed}.fid of user's picture.",
       ),
-      'init' => array(
-        'type' => 'varchar',
-        'length' => 254,
-        'not null' => FALSE,
-        'default' => '',
-        'description' => 'E-mail address used for initial account creation.',
-      ),
       'data' => array(
         'type' => 'blob',
         'not null' => FALSE,
@@ -149,7 +135,6 @@ function user_schema() {
     ),
     'unique keys' => array(
       'uuid' => array('uuid'),
-      'name' => array('name'),
     ),
     'primary key' => array('uid'),
     'foreign keys' => array(
@@ -160,6 +145,60 @@ function user_schema() {
     ),
   );
 
+  $schema['account'] = array(
+    'description' => 'Stores account data.',
+    'fields' => array(
+      'aid' => array(
+        'type' => 'serial',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'description' => 'Primary Key: Unique account ID',
+      ),
+      'uid' => array(
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+        'description' => "User's {users}.uid.",
+      ),
+      'username' => array(
+        'type' => 'varchar',
+        'length' => 60,
+        'not null' => TRUE,
+        'default' => '',
+        'description' => 'Unique user name.',
+      ),
+      'pass' => array(
+        'type' => 'varchar',
+        'length' => 128,
+        'not null' => TRUE,
+        'default' => '',
+        'description' => "User's password (hashed).",
+      ),
+      'created' => array(
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0,
+        'description' => 'Timestamp for when user was created.',
+      ),
+      'init' => array(
+        'type' => 'varchar',
+        'length' => 254,
+        'not null' => FALSE,
+        'default' => '',
+        'description' => 'E-mail address used for initial account creation.',
+      ),
+    ),
+    'indexes' => array(
+      'created' => array('created'),
+      'uid' => array('uid'),
+    ),
+    'unique keys' => array(
+      'username' => array('username'),
+    ),
+    'primary key' => array('aid'),
+  );
+
   $schema['authmap'] = array(
     'description' => 'Stores distributed authentication mapping.',
     'fields' => array(
@@ -599,5 +638,98 @@ function user_update_8009(&$sandbox) {
 }
 
 /**
+ * Split the users table into accounts and users and migrate users into new
+ * structure.
+ */
+function user_update_8010(&$sandbox) {
+  if (!isset($sandbox['progress'])) {
+    $schema = array(
+      'description' => 'Stores account data.',
+      'fields' => array(
+        'aid' => array(
+          'type' => 'serial',
+          'unsigned' => TRUE,
+          'not null' => TRUE,
+          'description' => 'Primary Key: Unique account ID',
+        ),
+        'uid' => array(
+          'type' => 'int',
+          'unsigned' => TRUE,
+          'not null' => TRUE,
+          'default' => 0,
+          'description' => "User's {users}.uid.",
+        ),
+        'username' => array(
+          'type' => 'varchar',
+          'length' => 60,
+          'not null' => TRUE,
+          'default' => '',
+          'description' => 'Unique user name.',
+        ),
+        'pass' => array(
+          'type' => 'varchar',
+          'length' => 128,
+          'not null' => TRUE,
+          'default' => '',
+          'description' => "User's password (hashed).",
+        ),
+        'created' => array(
+          'type' => 'int',
+          'not null' => TRUE,
+          'default' => 0,
+          'description' => 'Timestamp for when user was created.',
+        ),
+        'init' => array(
+          'type' => 'varchar',
+          'length' => 254,
+          'not null' => FALSE,
+          'default' => '',
+          'description' => 'E-mail address used for initial account creation.',
+        ),
+      ),
+      'indexes' => array(
+        'created' => array('created'),
+        'uid' => array('uid'),
+      ),
+      'unique keys' => array(
+        'username' => array('username'),
+      ),
+      'primary key' => array('aid'),
+    );
+    db_create_table('account', $schema);
+
+    // Set up the batch.
+    $sandbox['progress'] = 0;
+    // The anonymous user doesn't need an account to we start at 1.
+    // @todo: Do we need to make a stock anonymous user anymore?
+    $sandbox['last'] = 0;
+    $sandbox['max'] = db_query('SELECT COUNT(uid) FROM {users} WHERE uid > 0')->fetchField();
+  }
+
+  $users = db_query_range('SELECT * FROM {users} WHERE uid > :uid ORDER BY uid ASC', 0, 10, array(':uid' => $sandbox['last']))->fetchAllAssoc('uid');
+
+  foreach ($users as $uid => $user) {
+    db_insert('account')
+      ->fields( array(
+        'uid' => $user->uid,
+        'username' => $user->name,
+        'pass' => $user->pass,
+        'created' => $user->created,
+        'init' => $user->init,
+      ))
+      ->execute();
+    $sandbox['last'] = $user->uid;
+  }
+
+  $sandbox['#finished'] = empty($sandbox['max']) ? 1 : ($sandbox['last'] / $sandbox['max']);
+
+  // When the migrate has finished clean up the user table.
+  if ($sandbox['#finished'] == 1) {
+    db_drop_field('users', 'pass');
+    db_drop_field('users', 'init');
+  }
+}
+
+/**
  * @} End of "addtogroup updates-7.x-to-8.x".
  */
diff --git a/core/modules/user/user.module b/core/modules/user/user.module
index e42002b..16e8394 100644
--- a/core/modules/user/user.module
+++ b/core/modules/user/user.module
@@ -147,8 +147,7 @@ function user_entity_info() {
       'label' => t('User'),
       'controller class' => 'Drupal\user\UserStorageController',
       'form controller class' => array(
-        'profile' => 'Drupal\user\ProfileFormController',
-        'register' => 'Drupal\user\RegisterFormController',
+        'settings' => 'Drupal\user\SettingsFormController',
       ),
       'base table' => 'users',
       'uri callback' => 'user_uri',
@@ -175,11 +174,54 @@ function user_entity_info() {
         ),
       ),
     ),
+    'account' => array(
+      'label' => t('Account'),
+      'controller class' => 'Drupal\user\AccountStorageController',
+      'form controller class' => array(
+        'profile' => 'Drupal\user\ProfileFormController',
+        'register' => 'Drupal\user\RegisterFormController',
+      ),
+      'base table' => 'account',
+      'uri callback' => 'account_uri',
+      'label callback' => 'account_label',
+      'fieldable' => FALSE,
+      'entity class' => 'Drupal\user\Account',
+      'entity keys' => array(
+        'id' => 'aid',
+      ),
+    ),
   );
 }
 
 /**
- * Entity URI callback.
+ * Entity URI callback for accounts.
+ */
+function account_uri($account) {
+  return array(
+    'path' => 'user/' . $account->uid,
+  );
+}
+
+/**
+ * Entity label callback for accounts.
+ *
+ * This label callback has langcode for security reasons. The username is the
+ * visual identifier for an account.
+ *
+ * @param $entity_type
+ *   The entity type.
+ * @param $entity
+ *   The entity object.
+ *
+ * @return
+ *   The username on the account.
+ */
+function account_label($entity_type, $entity) {
+  return $entity->username;
+}
+
+/**
+ * Entity URI callback for users.
  */
 function user_uri($user) {
   return array(
@@ -226,11 +268,6 @@ function user_field_info_alter(&$info) {
 function user_field_extra_fields() {
   $return['user']['user'] = array(
     'form' => array(
-      'account' => array(
-        'label' => t('User name and password'),
-        'description' => t('User module account form elements.'),
-        'weight' => -10,
-      ),
       'timezone' => array(
         'label' => t('Timezone'),
         'description' => t('User module timezone form element.'),
@@ -340,25 +377,40 @@ function user_load_by_mail($mail) {
 }
 
 /**
- * Fetches a user object by account name.
+ * Fetches a user object by username.
  *
- * @param string $name
- *   String with the account's user name.
+ * @param string $username
+ *   String with the account's username.
  * @return object|bool
  *   A fully-loaded $user object upon successful user load or FALSE if user
  *   cannot be loaded.
  *
- * @see user_load_multiple()
+ * @see user_load()
+ * @see account_load_by_name()
  */
-function user_load_by_name($name) {
-  $users = entity_load_multiple_by_properties('user', array('name' => $name));
-  return reset($users);
+function user_load_by_name($username) {
+  $account = account_load_by_name($username);
+  return user_load($account->uid);
+}
+
+/**
+ * Fetches an account object by username.
+ *
+ * @param string $username
+ *   String with the account's username.
+ * @return object|bool
+ *   A fully-loaded $account object upon successful user load or FALSE if user
+ *   cannot be loaded.
+ */
+function account_load_by_name($username) {
+  $accounts = entity_load_multiple_by_properties('account', array('username' => $username));
+  return reset($accounts);
 }
 
 /**
  * Verify the syntax of the given name.
  */
-function user_validate_name($name) {
+function account_validate_name($name) {
   if (!$name) {
     return t('You must enter a username.');
   }
@@ -417,7 +469,7 @@ function user_validate_picture(&$form, &$form_state) {
 /**
  * Generate a random alphanumeric password.
  */
-function user_password($length = 10) {
+function account_password($length = 10) {
   // This variable contains the list of allowable characters for the
   // password. Note that the number 0 and the letter 'O' have been
   // removed to avoid confusion between the two. The same is true
@@ -538,18 +590,19 @@ function user_access($string, $account = NULL) {
 /**
  * Checks for usernames blocked by user administration.
  *
- * @param $name
- *   A string containing a name of the user.
+ * @param $username
+ *   A string containing a username of the account.
  *
  * @return
- *   Object with property 'name' (the user name), if the user is blocked;
- *   FALSE if the user is not blocked.
- */
-function user_is_blocked($name) {
-  return db_select('users')
-    ->fields('users', array('name'))
-    ->condition('name', db_like($name), 'LIKE')
-    ->condition('status', 0)
+ *   Object with property 'username' (the user name), if the account is
+ *   blocked; FALSE if the user is not blocked.
+ */
+function user_is_blocked($username) {
+  $query = db_select('account');
+  $query->join('users', 'users', 'users.uid = account.uid');
+  return $query->fields('account', array('username'))
+    ->condition('account.username', db_like($username), 'LIKE')
+    ->condition('users.status', 0)
     ->execute()->fetchObject();
 }
 
@@ -687,12 +740,15 @@ function user_user_view($account) {
     '#markup' => theme('user_picture', array('account' => $account)),
     '#weight' => -10,
   );
-  $account->content['member_for'] = array(
-    '#type' => 'item',
-    '#title' => t('Member for'),
-    '#markup' => format_interval(REQUEST_TIME - $account->created),
-    '#weight' => 5,
-  );
+  $account_account = account_uid_load($account->uid);
+  if ($account_account) {
+    $account->content['member_for'] = array(
+      '#type' => 'item',
+      '#title' => t('Member for'),
+      '#markup' => format_interval(REQUEST_TIME - $account_account->created),
+      '#weight' => 5,
+    );
+  }
 }
 
 /**
@@ -735,7 +791,7 @@ function user_login_block($form) {
   $form['#id'] = 'user-login-form';
   $form['#validate'] = user_login_default_validators();
   $form['#submit'][] = 'user_login_submit';
-  $form['name'] = array('#type' => 'textfield',
+  $form['username'] = array('#type' => 'textfield',
     '#title' => t('Username'),
     '#maxlength' => USERNAME_MAX_LENGTH,
     '#size' => 15,
@@ -849,7 +905,7 @@ function user_block_view($delta = '') {
     case 'new':
       if (user_access('access content')) {
         // Retrieve a list of new users who have subsequently accessed the site successfully.
-        $items = db_query_range('SELECT uid, name FROM {users} WHERE status <> 0 AND access <> 0 ORDER BY created DESC', 0, variable_get('user_block_whois_new_count', 5))->fetchAll();
+        $items = db_query_range('SELECT uid, name FROM {users} WHERE status <> 0 AND login <> 0 ORDER BY created DESC', 0, variable_get('user_block_whois_new_count', 5))->fetchAll();
 
         $block['subject'] = t('Who\'s new');
         $block['content'] = array(
@@ -917,21 +973,21 @@ function user_preprocess_block(&$variables) {
  * By default, the passed-in object's 'name' property is used if it exists, or
  * else, the site-defined value for the 'anonymous' variable. However, a module
  * may override this by implementing
- * hook_user_format_name_alter(&$name, $account).
+ * hook_user_format_name_alter(&$name, $user).
  *
  * @see hook_user_format_name_alter()
  *
- * @param $account
- *   The account object for the user whose name is to be formatted.
+ * @param $user
+ *   The user object for the user whose name is to be formatted.
  *
  * @return
  *   An unsanitized string with the username to display. The code receiving
  *   this result must ensure that check_plain() is called on it before it is
  *   printed to the page.
  */
-function user_format_name($account) {
-  $name = !empty($account->name) ? $account->name : config('user.settings')->get('anonymous');
-  drupal_alter('user_format_name', $name, $account);
+function user_format_name($user) {
+  $name = !empty($user->name) ? $user->name : config('user.settings')->get('anonymous');
+  drupal_alter('user_format_name', $name, $user);
   return $name;
 }
 
@@ -1104,7 +1160,7 @@ function user_is_logged_in() {
 }
 
 function user_register() {
-  $account = entity_create('user', array());
+  $account = entity_create('account', array());
   return entity_get_form($account, 'register');
 }
 
@@ -1347,12 +1403,35 @@ function user_menu() {
   $items['user/%user/edit'] = array(
     'title' => 'Edit',
     'page callback' => 'entity_get_form',
+    'page arguments' => array(1, 'settings'),
+    'access callback' => 'user_edit_access',
+    'access arguments' => array(1),
+    'type' => MENU_LOCAL_TASK,
+    'file' => 'user.pages.inc',
+  );
+
+  $items['user/%user/edit/user'] = array(
+    'title' => 'User',
+    'page callback' => 'entity_get_form',
+    'page arguments' => array(1, 'settings'),
+    'access callback' => 'user_edit_access',
+    'access arguments' => array(1),
+    'type' => MENU_DEFAULT_LOCAL_TASK,
+    'file' => 'user.pages.inc',
+    'weight' => 98,
+  );
+
+  $items['user/%account_uid/edit/account'] = array(
+    'title' => 'Account',
+    'page callback' => 'entity_get_form',
     'page arguments' => array(1, 'profile'),
     'access callback' => 'user_edit_access',
     'access arguments' => array(1),
     'type' => MENU_LOCAL_TASK,
     'file' => 'user.pages.inc',
+    'weight' => 99,
   );
+
   return $items;
 }
 
@@ -1494,6 +1573,27 @@ function user_uid_optional_to_arg($arg) {
 }
 
 /**
+ * Load either a specified or the current user account.
+ *
+ * @param $uid
+ *   An optional user ID of the user to load. If not provided, the current
+ *   user's ID will be used.
+ * @return
+ *   A fully-loaded $user object upon successful user load, FALSE if user
+ *   cannot be loaded.
+ *
+ * @see account_load()
+ * @todo rethink the naming of this in Drupal 8.
+ */
+function account_uid_load($uid = NULL) {
+  if (!isset($uid)) {
+    $uid = $GLOBALS['user']->uid;
+  }
+  $accounts = entity_load_multiple_by_properties('account', array('uid' => $uid));
+  return reset($accounts);
+}
+
+/**
  * Menu item title callback for the 'user' path.
  *
  * Anonymous users should see a title based on the requested page, but
@@ -1585,7 +1685,7 @@ function user_login($form, &$form_state) {
   }
 
   // Display login form:
-  $form['name'] = array('#type' => 'textfield',
+  $form['username'] = array('#type' => 'textfield',
     '#title' => t('Username'),
     '#size' => 60,
     '#maxlength' => USERNAME_MAX_LENGTH,
@@ -1595,7 +1695,7 @@ function user_login($form, &$form_state) {
     ),
   );
 
-  $form['name']['#description'] = t('Enter your @s username.', array('@s' => config('system.site')->get('name')));
+  $form['username']['#description'] = t('Enter your @s username.', array('@s' => config('system.site')->get('name')));
   $form['pass'] = array('#type' => 'password',
     '#title' => t('Password'),
     '#description' => t('Enter the password that accompanies your username.'),
@@ -1634,9 +1734,9 @@ function user_login_default_validators() {
  * A FAPI validate handler. Sets an error if supplied username has been blocked.
  */
 function user_login_name_validate($form, &$form_state) {
-  if (isset($form_state['values']['name']) && user_is_blocked($form_state['values']['name'])) {
+  if (isset($form_state['values']['username']) && user_is_blocked($form_state['values']['username'])) {
     // Blocked in user administration.
-    form_set_error('name', t('The username %name has not been activated or is blocked.', array('%name' => $form_state['values']['name'])));
+    form_set_error('username', t('The username %username has not been activated or is blocked.', array('%username' => $form_state['values']['username'])));
   }
 }
 
@@ -1648,7 +1748,7 @@ function user_login_name_validate($form, &$form_state) {
 function user_login_authenticate_validate($form, &$form_state) {
   $password = trim($form_state['values']['pass']);
   $flood_config = config('user.flood');
-  if (!empty($form_state['values']['name']) && !empty($password)) {
+  if (!empty($form_state['values']['username']) && !empty($password)) {
     // Do not allow any login from the current user's IP if the limit has been
     // reached. Default is 50 failed attempts allowed in one hour. This is
     // independent of the per-user limit to catch attempts from one IP to log
@@ -1658,7 +1758,7 @@ function user_login_authenticate_validate($form, &$form_state) {
       $form_state['flood_control_triggered'] = 'ip';
       return;
     }
-    $account = db_query("SELECT * FROM {users} WHERE name = :name AND status = 1", array(':name' => $form_state['values']['name']))->fetchObject();
+    $account = db_query("SELECT * FROM {account} a LEFT JOIN {users} u ON u.uid = a.uid WHERE a.username = :username AND u.status = 1", array(':username' => $form_state['values']['username']))->fetchObject();
     if ($account) {
       if ($flood_config->get('uid_only')) {
         // Register flood events based on the uid only, so they apply for any
@@ -1682,7 +1782,7 @@ function user_login_authenticate_validate($form, &$form_state) {
     }
     // We are not limited by flood control, so try to authenticate.
     // Set $form_state['uid'] as a flag for user_login_final_validate().
-    $form_state['uid'] = user_authenticate($form_state['values']['name'], $password);
+    $form_state['uid'] = user_authenticate($form_state['values']['username'], $password);
   }
 }
 
@@ -1705,16 +1805,16 @@ function user_login_final_validate($form, &$form_state) {
 
     if (isset($form_state['flood_control_triggered'])) {
       if ($form_state['flood_control_triggered'] == 'user') {
-        form_set_error('name', format_plural($flood_config->get('user_limit'), 'Sorry, there has been more than one failed login attempt for this account. It is temporarily blocked. Try again later or <a href="@url">request a new password</a>.', 'Sorry, there have been more than @count failed login attempts for this account. It is temporarily blocked. Try again later or <a href="@url">request a new password</a>.', array('@url' => url('user/password'))));
+        form_set_error('username', format_plural($flood_config->get('user_limit'), 'Sorry, there has been more than one failed login attempt for this account. It is temporarily blocked. Try again later or <a href="@url">request a new password</a>.', 'Sorry, there have been more than @count failed login attempts for this account. It is temporarily blocked. Try again later or <a href="@url">request a new password</a>.', array('@url' => url('user/password'))));
       }
       else {
         // We did not find a uid, so the limit is IP-based.
-        form_set_error('name', t('Sorry, too many failed login attempts from your IP address. This IP address is temporarily blocked. Try again later or <a href="@url">request a new password</a>.', array('@url' => url('user/password'))));
+        form_set_error('username', t('Sorry, too many failed login attempts from your IP address. This IP address is temporarily blocked. Try again later or <a href="@url">request a new password</a>.', array('@url' => url('user/password'))));
       }
     }
     else {
-      form_set_error('name', t('Sorry, unrecognized username or password. <a href="@password">Have you forgotten your password?</a>', array('@password' => url('user/password'))));
-      watchdog('user', 'Login attempt failed for %user.', array('%user' => $form_state['values']['name']));
+      form_set_error('username', t('Sorry, unrecognized username or password. <a href="@password">Have you forgotten your password?</a>', array('@password' => url('user/password'))));
+      watchdog('user', 'Login attempt failed for %user.', array('%user' => $form_state['values']['username']));
     }
   }
   elseif (isset($form_state['flood_control_user_identifier'])) {
@@ -1734,10 +1834,10 @@ function user_login_final_validate($form, &$form_state) {
  * @return
  *   The user's uid on success, or FALSE on failure to authenticate.
  */
-function user_authenticate($name, $password) {
+function user_authenticate($username, $password) {
   $uid = FALSE;
-  if (!empty($name) && !empty($password)) {
-    $account = user_load_by_name($name);
+  if (!empty($username) && !empty($password)) {
+    $account = account_load_by_name($username);
     if ($account) {
       // Allow alternate password hashing schemes.
       require_once DRUPAL_ROOT . '/' . variable_get('password_inc', 'core/includes/password.inc');
@@ -1838,7 +1938,7 @@ function user_external_login_register($name, $module) {
  *   A unique URL that provides a one-time log in for the user, from which
  *   they can change their password.
  */
-function user_pass_reset_url($account, $options = array()) {
+function account_pass_reset_url($account, $options = array()) {
   $timestamp = REQUEST_TIME;
   $langcode = isset($options['langcode']) ? $options['langcode'] : user_preferred_langcode($account);
   $url_options = array('absolute' => TRUE, 'language' => language_load($langcode));
@@ -2169,7 +2269,7 @@ function _user_mail_text($key, $langcode = NULL, $variables = array()) {
  */
 function user_mail_tokens(&$replacements, $data, $options) {
   if (isset($data['user'])) {
-    $replacements['[user:one-time-login-url]'] = user_pass_reset_url($data['user'], $options);
+    $replacements['[user:one-time-login-url]'] = account_pass_reset_url($data['user'], $options);
     $replacements['[user:cancel-url]'] = user_cancel_url($data['user'], $options);
   }
 }
diff --git a/core/modules/user/user.tokens.inc b/core/modules/user/user.tokens.inc
index bc37434..a3d02bd 100644
--- a/core/modules/user/user.tokens.inc
+++ b/core/modules/user/user.tokens.inc
@@ -11,7 +11,7 @@
 function user_token_info() {
   $types['user'] = array(
     'name' => t('Users'),
-    'description' => t('Tokens related to individual user accounts.'),
+    'description' => t('Tokens related to individual users.'),
     'needs-data' => 'user',
   );
   $types['current-user'] = array(
@@ -22,23 +22,23 @@ function user_token_info() {
 
   $user['uid'] = array(
     'name' => t('User ID'),
-    'description' => t("The unique ID of the user account."),
+    'description' => t("The unique ID of the user."),
   );
   $user['name'] = array(
     'name' => t("Name"),
-    'description' => t("The login name of the user account."),
+    'description' => t("The nice name of the user."),
   );
   $user['mail'] = array(
     'name' => t("Email"),
-    'description' => t("The email address of the user account."),
+    'description' => t("The email address of the user."),
   );
   $user['url'] = array(
     'name' => t("URL"),
-    'description' => t("The URL of the account profile page."),
+    'description' => t("The URL of the user profile page."),
   );
   $user['edit-url'] = array(
     'name' => t("Edit URL"),
-    'description' => t("The URL of the account edit page."),
+    'description' => t("The URL of the user edit page."),
   );
 
   $user['last-login'] = array(
@@ -48,13 +48,39 @@ function user_token_info() {
   );
   $user['created'] = array(
     'name' => t("Created"),
+    'description' => t("The date the user user was created."),
+    'type' => 'date',
+  );
+
+  $types['account'] = array(
+    'name' => t('Accounts'),
+    'description' => t('Tokens related to individual user accounts.'),
+    'needs-data' => 'account',
+  );
+  $account['aid'] = array(
+    'name' => t('Account ID'),
+    'description' => t("The unique ID of the user account."),
+  );
+  $account['uid'] = array(
+    'name' => t('User ID'),
+    'description' => t("The user ID of this account."),
+  );
+  $account['username'] = array(
+    'name' => t("Name"),
+    'description' => t("The login name of the user account."),
+  );
+  $account['created'] = array(
+    'name' => t("Created"),
     'description' => t("The date the user account was created."),
     'type' => 'date',
   );
 
   return array(
     'types' => $types,
-    'tokens' => array('user' => $user),
+    'tokens' => array(
+      'user' => $user,
+      'account' => $account,
+    ),
   );
 }
 
@@ -127,5 +153,36 @@ function user_tokens($type, $tokens, array $data = array(), array $options = arr
     $replacements += token_generate('user', $tokens, array('user' => $account), $options);
   }
 
+  if ($type == 'account' && !empty($data['account'])) {
+    $account = $data['account'];
+    foreach ($tokens as $name => $original) {
+      switch ($name) {
+        // Basic account information.
+        case 'aid':
+          // In the case of hook user_presave aid is not set yet.
+          $replacements[$original] = !empty($account->aid) ? $account->aid : t('not yet assigned');
+          break;
+
+        case 'uid':
+          // In the case of hook user_presave uid is not set yet.
+          $replacements[$original] = !empty($account->uid) ? $account->uid : t('not yet assigned');
+          break;
+
+        case 'username':
+          $replacements[$original] = $sanitize ? check_plain($account->username) : $account->username;
+          break;
+
+        case 'created':
+          // In the case of user_presave the created date may not yet be set.
+          $replacements[$original] = !empty($account->created) ? format_date($account->created, 'medium', '', NULL, $langcode) : t('not yet created');
+          break;
+      }
+    }
+
+    if ($registered_tokens = token_find_with_prefix($tokens, 'created')) {
+      $replacements += token_generate('date', $registered_tokens, array('date' => $account->created), $options);
+    }
+  }
+
   return $replacements;
 }
