diff --git a/core/lib/Drupal/Core/Render/Element/PasswordConfirm.php b/core/lib/Drupal/Core/Render/Element/PasswordConfirm.php
index 98b65ed..f135a93 100644
--- a/core/lib/Drupal/Core/Render/Element/PasswordConfirm.php
+++ b/core/lib/Drupal/Core/Render/Element/PasswordConfirm.php
@@ -14,6 +14,7 @@
  * @code
  * $form['pass'] = array(
  *   '#type' => 'password_confirm',
+ *   '#title1' => t('New password'),
  *   '#title' => $this->t('Password'),
  *   '#size' => 25,
  * );
@@ -67,7 +68,7 @@ public static function valueCallback(&$element, $input, FormStateInterface $form
   public static function processPasswordConfirm(&$element, FormStateInterface $form_state, &$complete_form) {
     $element['pass1'] = array(
       '#type' => 'password',
-      '#title' => t('Password'),
+      '#title' => !empty($element['#title1']) ? $element['#title1'] : t('Password'),
       '#value' => empty($element['#value']) ? NULL : $element['#value']['pass1'],
       '#required' => $element['#required'],
       '#attributes' => array('class' => array('password-field', 'js-password-field')),
@@ -75,11 +76,19 @@ public static function processPasswordConfirm(&$element, FormStateInterface $for
     );
     $element['pass2'] = array(
       '#type' => 'password',
-      '#title' => t('Confirm password'),
+      '#title' => !empty($element['#title2']) ? $element['#title2'] : t('Confirm password'),
       '#value' => empty($element['#value']) ? NULL : $element['#value']['pass2'],
       '#required' => $element['#required'],
       '#attributes' => array('class' => array('password-confirm', 'js-password-confirm')),
       '#error_no_message' => TRUE,
+      '#states' => array(
+        'visible' => array(
+          ':input[name="pass[pass1]"]' => ['filled' => TRUE],
+        ),
+        'required' => array(
+          ':input[name="pass[pass1]"]' => ['filled' => TRUE],
+        ),
+      ),
     );
     $element['#element_validate'] = array(array(get_called_class(), 'validatePasswordConfirm'));
     $element['#tree'] = TRUE;
diff --git a/core/modules/user/src/AccountForm.php b/core/modules/user/src/AccountForm.php
index dbdb08b..ae8ef1d 100644
--- a/core/modules/user/src/AccountForm.php
+++ b/core/modules/user/src/AccountForm.php
@@ -81,18 +81,6 @@ public function form(array $form, FormStateInterface $form_state) {
       '#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 email address to be edited and deleted.
-    // Also see \Drupal\user\Plugin\Validation\Constraint\UserMailRequired.
-    $form['account']['mail'] = array(
-      '#type' => 'email',
-      '#title' => $this->t('Email address'),
-      '#description' => $this->t('A valid email address. All emails from the system will be sent to this address. The email 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 email.'),
-      '#required' => !(!$account->getEmail() && $user->hasPermission('administer users')),
-      '#default_value' => (!$register ? $account->getEmail() : ''),
-    );
-
     // Only show name field on registration form or user can change own username.
     $form['account']['name'] = array(
       '#type' => 'textfield',
@@ -108,25 +96,25 @@ public function form(array $form, FormStateInterface $form_state) {
       ),
       '#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 email address to be edited and deleted.
+    // Also see \Drupal\user\Plugin\Validation\Constraint\UserMailRequired.
+    $form['account']['mail'] = array(
+      '#type' => 'email',
+      '#title' => $this->t('Email address'),
+      '#description' => $this->t('A valid email address. All emails from the system will be sent to this address. The email 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 email. In case you want to change this email address you also need to confirm your current password.'),
+      '#required' => !(!$account->getEmail() && $user->hasPermission('administer users')),
+      '#default_value' => (!$register ? $account->getEmail() : ''),
+      '#weight' => -9,
     );
 
     // 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.'),
-      );
-
-      // To skip the current password field, the user must have logged in via a
-      // one-time link and have the token in the URL. Store this in $form_state
-      // so it persists even on subsequent Ajax requests.
-      if (!$form_state->get('user_pass_reset') && ($token = $this->getRequest()->get('pass-reset-token'))) {
-        $session_key = 'pass_reset_' . $account->id();
-        $user_pass_reset = isset($_SESSION[$session_key]) && Crypt::hashEquals($_SESSION[$session_key], $token);
-        $form_state->set('user_pass_reset', $user_pass_reset);
-      }
 
       // The user must enter their current password to change to a new one.
       if ($user->id() == $account->id()) {
@@ -135,7 +123,7 @@ public function form(array $form, FormStateInterface $form_state) {
           '#title' => $this->t('Current password'),
           '#size' => 25,
           '#access' => !$form_state->get('user_pass_reset'),
-          '#weight' => -5,
+          '#weight' => -8,
           // Do not let web browsers remember this password, since we are
           // trying to confirm that the person submitting the form actually
           // knows the current one.
@@ -146,13 +134,44 @@ public function form(array $form, FormStateInterface $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 (!$form_state->get('user_pass_reset')) {
-          $form['account']['current_pass']['#description'] = $this->t('Required if you want to change the %mail or %pass below. <a href=":request_new_url" title="Send password reset instructions via email.">Reset your password</a>.', array(
+          $form['account']['current_pass']['#description'] = $this->t('Confirm your current password to change the %mail or to set a %pass. <a href=":request_new_url" title="Send password reset instructions via email.">Reset your password</a>.', array(
             '%mail' => $form['account']['mail']['#title'],
-            '%pass' => $this->t('Password'),
+            '%pass' => $this->t('New password'),
             ':request_new_url' => $this->url('user.pass'),
           ));
+          $form['account']['current_pass']['#states'] = [
+            // Only show this field when mail or new password has changed.
+            'visible' => [
+              [':input[name="mail"]' => ['!value' => $account->getEmail()]],
+              [':input[name="pass[pass1]"]' => ['filled' => TRUE]],
+            ],
+            // Mark the field as required if mail or password has changed.
+            'required' => [
+              [':input[name="mail"]' => ['!value' => $account->getEmail()]],
+              [':input[name="pass[pass1]"]' => ['filled' => TRUE]],
+            ],
+          ];
         }
       }
+
+      $form['account']['pass'] = array(
+        '#type' => 'password_confirm',
+        '#prefix' => '<h3>' . $this->t('Change password') . '</h3>',
+        '#title1' => $this->t('New password'),
+        '#title2' => $this->t('Confirm new password'),
+        '#size' => 25,
+        '#description' => $this->t('To change the current user password, enter the new password here. To be allowed to do this you also need to confirm your current password.'),
+        '#weight' => -7,
+      );
+
+      // To skip the current password field, the user must have logged in via a
+      // one-time link and have the token in the URL. Store this in $form_state
+      // so it persists even on subsequent Ajax requests.
+      if (!$form_state->get('user_pass_reset') && ($token = $this->getRequest()->get('pass-reset-token'))) {
+        $session_key = 'pass_reset_' . $account->id();
+        $user_pass_reset = isset($_SESSION[$session_key]) && Crypt::hashEquals($_SESSION[$session_key], $token);
+        $form_state->set('user_pass_reset', $user_pass_reset);
+      }
     }
     elseif (!$config->get('verify_mail') || $admin) {
       $form['account']['pass'] = array(
diff --git a/core/modules/user/src/Tests/UserEditTest.php b/core/modules/user/src/Tests/UserEditTest.php
index 225b194..5d23772 100644
--- a/core/modules/user/src/Tests/UserEditTest.php
+++ b/core/modules/user/src/Tests/UserEditTest.php
@@ -42,7 +42,7 @@ function testUserEdit() {
     $edit = array();
     $edit['mail'] = $this->randomMachineName() . '@new.example.com';
     $this->drupalPostForm("user/" . $user1->id() . "/edit", $edit, t('Save'));
-    $this->assertRaw(t("Your current password is missing or incorrect; it's required to change the %name.", array('%name' => t('Email'))));
+    $this->assertRaw(t("Your current password is missing or incorrect; it's required to change the %name.", array('%name' => 'Email')));
 
     $edit['current_pass'] = $user1->pass_raw;
     $this->drupalPostForm("user/" . $user1->id() . "/edit", $edit, t('Save'));
@@ -53,7 +53,7 @@ function testUserEdit() {
     $edit['pass[pass1]'] = $new_pass = $this->randomMachineName();
     $edit['pass[pass2]'] = $new_pass;
     $this->drupalPostForm("user/" . $user1->id() . "/edit", $edit, t('Save'));
-    $this->assertRaw(t("Your current password is missing or incorrect; it's required to change the %name.", array('%name' => t('Password'))));
+    $this->assertRaw(t("Your current password is missing or incorrect; it's required to change the %name.", array('%name' => 'Password')));
 
     // Try again with the current password.
     $edit['current_pass'] = $user1->pass_raw;
diff --git a/core/modules/user/src/Tests/UserPasswordResetTest.php b/core/modules/user/src/Tests/UserPasswordResetTest.php
index af8f56c..45419dc 100644
--- a/core/modules/user/src/Tests/UserPasswordResetTest.php
+++ b/core/modules/user/src/Tests/UserPasswordResetTest.php
@@ -120,7 +120,7 @@ function testUserPasswordReset() {
 
     // Verify that the password reset session has been destroyed.
     $this->drupalPostForm(NULL, $edit, t('Save'));
-    $this->assertText(t('Your current password is missing or incorrect; it\'s required to change the Password.'), 'Password needed to make profile changes.');
+    $this->assertRaw(t("Your current password is missing or incorrect; it's required to change the %name.", array('%name' => 'Password')), 'Password needed to make profile changes.');
 
     // Log out, and try to log in again using the same one-time link.
     $this->drupalLogout();
diff --git a/core/modules/user/tests/src/Kernel/UserAccountFormFieldsTest.php b/core/modules/user/tests/src/Kernel/UserAccountFormFieldsTest.php
index 4a83c41..31abe83 100644
--- a/core/modules/user/tests/src/Kernel/UserAccountFormFieldsTest.php
+++ b/core/modules/user/tests/src/Kernel/UserAccountFormFieldsTest.php
@@ -33,7 +33,7 @@ function testInstallConfigureForm() {
       ->buildForm('Drupal\Core\Installer\Form\SiteConfigureForm', $form_state);
 
     // Verify name and pass field order.
-    $this->assertFieldOrder($form['admin_account']['account']);
+    $this->assertSiteConfigureFormFieldOrder($form['admin_account']['account']);
 
     // Verify that web browsers may autocomplete the email value and
     // autofill/prefill the name and pass values.
@@ -56,8 +56,8 @@ function testUserRegistrationForm() {
 
     $form = $this->buildAccountForm('register');
 
-    // Verify name and pass field order.
-    $this->assertFieldOrder($form['account']);
+    // Verify name, email and pass field order.
+    $this->assertAccountFieldOrder($form['account']);
 
     // Verify that web browsers may autocomplete the email value and
     // autofill/prefill the name and pass values.
@@ -78,8 +78,8 @@ function testUserEditForm() {
 
     $form = $this->buildAccountForm('default');
 
-    // Verify name and pass field order.
-    $this->assertFieldOrder($form['account']);
+    // Verify name, mail and pass field order.
+    $this->assertAccountFieldOrder($form['account']);
 
     // Verify that autocomplete is off on all account fields.
     foreach (array('mail', 'name', 'pass') as $key) {
@@ -93,7 +93,7 @@ function testUserEditForm() {
    * @param array $elements
    *   A form array section that contains the user account form elements.
    */
-  protected function assertFieldOrder(array $elements) {
+  protected function assertSiteConfigureFormFieldOrder(array $elements) {
     $name_index = 0;
     $name_weight = 0;
     $pass_index = 0;
@@ -112,11 +112,56 @@ protected function assertFieldOrder(array $elements) {
       }
       $index++;
     }
-    $this->assertEqual($name_index, $pass_index - 1, "'name' field ($name_index) appears before 'pass' field ($pass_index).");
+    $this->assertEquals($name_index, $pass_index - 1, "'name' field ($name_index) appears before 'pass' field ($pass_index).");
     $this->assertTrue($name_weight < $pass_weight, "'name' field weight ($name_weight) is smaller than 'pass' field weight ($pass_weight).");
   }
 
   /**
+   * Asserts the correct order of name, mail and pass fields.
+   *
+   * @param array $elements
+   *   A form array section that contains the user account form elements.
+   */
+  protected function assertAccountFieldOrder(array $elements) {
+    $name_index = 0;
+    $name_weight = 0;
+    $mail_index = 0;
+    $mail_weight = 0;
+    $pass_index = 0;
+    $pass_weight = 0;
+    $index = 0;
+
+    foreach ($elements as $key => $element) {
+      switch ($key) {
+        case 'name':
+          $name_index = $index;
+          $name_weight = $element['#weight'];
+          $this->assertTrue($element['#sorted'], "'name' field is #sorted.");
+          break;
+
+        case 'mail':
+          $mail_index = $index;
+          $mail_weight = $element['#weight'];
+          $this->assertTrue($element['#sorted'], "'mail' field is #sorted.");
+          break;
+
+        case 'pass':
+          $pass_index = $index;
+          $pass_weight = $element['#weight'];
+          $this->assertTrue($element['#sorted'], "'pass' field is #sorted.");
+          break;
+      }
+      $index++;
+    }
+
+    $this->assertEquals($name_index, $mail_index - 1, "'name' field ($name_index) appears before 'mail' field ($mail_index).");
+    $this->assertEquals($mail_index, $pass_index - 1, "'mail' field ($mail_index) appears before 'pass' field ($pass_index).");
+    $this->assertTrue($name_weight < $mail_weight, "'name' field weight ($name_weight) is smaller than 'mail' field weight ($mail_weight).");
+    $this->assertTrue($mail_weight < $pass_weight, "'mail' field weight ($mail_weight) is smaller than 'pass' field weight ($pass_weight).");
+  }
+
+
+  /**
    * Builds the user account form for a given operation.
    *
    * @param string $operation
