diff --git a/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php b/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php
index f886992..df6a421 100644
--- a/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php
+++ b/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php
@@ -621,16 +621,18 @@ protected function checkPermissions(array $permissions, $reset = FALSE) {
    *
    * @param $account
    *   User object representing the user to log in.
+   * @param $by_email
+   *   Whether to use email for login instead of username.
    *
    * @see drupalCreateUser()
    */
-  protected function drupalLogin($account) {
+  protected function drupalLogin($account, $by_email = FALSE) {
     if ($this->loggedInUser) {
       $this->drupalLogout();
     }
 
     $edit = array(
-      'name' => $account->name,
+      'name' => $by_email ? $user->mail : $user->name,
       'pass' => $account->pass_raw
     );
     $this->drupalPost('user', $edit, t('Log in'));
diff --git a/core/modules/user/config/user.settings.yml b/core/modules/user/config/user.settings.yml
index 3b53e41..89ef911 100644
--- a/core/modules/user/config/user.settings.yml
+++ b/core/modules/user/config/user.settings.yml
@@ -1,5 +1,6 @@
 admin_role: ''
 anonymous: Anonymous
+user_login_method: username_only
 verify_mail: '1'
 notify:
   cancel_confirm: '1'
diff --git a/core/modules/user/lib/Drupal/user/Tests/UserLoginTest.php b/core/modules/user/lib/Drupal/user/Tests/UserLoginTest.php
index 36c5f47..7e88b73 100644
--- a/core/modules/user/lib/Drupal/user/Tests/UserLoginTest.php
+++ b/core/modules/user/lib/Drupal/user/Tests/UserLoginTest.php
@@ -22,6 +22,33 @@ public static function getInfo() {
     );
   }
 
+
+  /**
+   * Test that login credentials work.
+   */
+  function testLoginByEmail() {
+    $account = $this->drupalCreateUser(array());
+
+    // Login via name.
+    $this->drupalLogin($account);
+    $this->assertFailedLogin($account, NULL, TRUE);
+
+    // Login via email only.
+    config('user.settings')
+      ->set('user_login_method', USER_LOGIN_EMAIL_ONLY)
+      ->save();
+    $this->drupalLogin($account, TRUE);
+    $this->assertFailedLogin($account);
+
+    // Login via name or email.
+    config('user.settings')
+      ->set('user_login_method', USER_LOGIN_USERNAME_OR_EMAIL)
+      ->save();;
+    $this->drupalLogin($account, TRUE);
+    $this->drupalLogin($account);
+
+  }
+
   /**
    * Test the global login flood control.
    */
@@ -139,10 +166,15 @@ function testPasswordRehashOnLogin() {
    * @param $flood_trigger
    *   Whether or not to expect that the flood control mechanism will be
    *   triggered.
+   * @param $by_email
+   *   Authenticate with email instead of username.
    */
-  function assertFailedLogin($account, $flood_trigger = NULL) {
+  function assertFailedLogin($account, $flood_trigger = NULL, $by_email = FALSE) {
+    if ($this->loggedInUser) {
+      $this->drupalLogout();
+    }
     $edit = array(
-      'name' => $account->name,
+      'name' => $by_email ? $account->mail : $account->name,
       'pass' => $account->pass_raw,
     );
     $this->drupalPost('user', $edit, t('Log in'));
@@ -157,7 +189,22 @@ function assertFailedLogin($account, $flood_trigger = NULL) {
       }
     }
     else {
-      $this->assertText(t('Sorry, unrecognized username or password. Have you forgotten your password?'));
+      switch (config('user.settings')->get('user_login_method')) {
+        case USER_LOGIN_USERNAME_ONLY:
+          $this->assertText(t('Sorry, unrecognized username or password. Have you forgotten your password?'));
+          break;
+        case USER_LOGIN_EMAIL_ONLY:
+          if (!$by_email) {
+            $this->assertText(t('The e-mail address @email is not valid.', array('@email' => $account->name)));
+          }
+          else {
+            $this->assertText(t('Sorry, unrecognized e-mail address or password. Have you forgotten your password?'));
+          }
+          break;
+        case USER_LOGIN_USERNAME_OR_EMAIL:
+          $this->assertText(t('Sorry, unrecognized username, e-mail address or password. Have you forgotten your password?'));
+        break;
+      }
     }
   }
 }
diff --git a/core/modules/user/user.admin.inc b/core/modules/user/user.admin.inc
index b8f6d42..4bcb312 100644
--- a/core/modules/user/user.admin.inc
+++ b/core/modules/user/user.admin.inc
@@ -340,6 +340,23 @@ function user_admin_settings($form, &$form_state) {
     $form['language'] += translation_entity_enable_widget('user', 'user', $form, $form_state);
   }
 
+  // User login settings.
+  $form['user_login'] = array(
+    '#type' => 'details',
+    '#title' => t('User login'),
+  );
+  $form['user_login']['user_login_method'] = array(
+    '#type' => 'select',
+    '#title' => t('Login credentials'),
+    '#description' => t('The details users may use to identify themselves.'),
+    '#options' => array(
+      USER_LOGIN_USERNAME_ONLY => t('Username'),
+      USER_LOGIN_EMAIL_ONLY => t('E-mail address'),
+      USER_LOGIN_USERNAME_OR_EMAIL => t('Username or e-mail address'),
+    ),
+    '#default_value' => $config->get('user_login_method'),
+  );
+
   // User registration settings.
   $form['registration_cancellation'] = array(
     '#type' => 'details',
@@ -635,6 +652,7 @@ function user_admin_settings_submit($form, &$form_state) {
   config('user.settings')
     ->set('anonymous', $form_state['values']['anonymous'])
     ->set('admin_role', $form_state['values']['user_admin_role'])
+    ->set('user_login_method', $form_state['values']['user_login_method'])
     ->set('register', $form_state['values']['user_register'])
     ->set('password_strength', $form_state['values']['user_password_strength'])
     ->set('verify_mail', $form_state['values']['user_email_verification'])
diff --git a/core/modules/user/user.module b/core/modules/user/user.module
index 5570313..f5a2086 100644
--- a/core/modules/user/user.module
+++ b/core/modules/user/user.module
@@ -26,6 +26,21 @@
 const EMAIL_MAX_LENGTH = 254;
 
 /**
+ * Users can login with username only.
+ */
+const USER_LOGIN_USERNAME_ONLY = 'username_only';
+
+/**
+ * Users can login with e-mail address only.
+ */
+const USER_LOGIN_EMAIL_ONLY = 'email_only';
+
+/**
+ * Users can login using either username or e-mail address.
+ */
+const USER_LOGIN_USERNAME_OR_EMAIL = 'username_or_email';
+
+/**
  * Only administrators can create user accounts.
  */
 const USER_REGISTER_ADMINISTRATORS_ONLY = 'admin_only';
@@ -1261,11 +1276,12 @@ function user_page_title($account) {
  */
 function user_login_form($form, &$form_state) {
   // Display login form:
+  $credentials = config('user.settings')->get('user_login_method');
   $form['name'] = array(
     '#type' => 'textfield',
-    '#title' => t('Username'),
+    '#title' => $credentials == USER_LOGIN_USERNAME_ONLY ? t('Username') : ($credentials == USER_LOGIN_EMAIL_ONLY ? t('E-mail address') : t('Username or e-mail address')),
     '#size' => 60,
-    '#maxlength' => USERNAME_MAX_LENGTH,
+    '#maxlength' => $credentials == USER_LOGIN_USERNAME_ONLY ? USERNAME_MAX_LENGTH : EMAIL_MAX_LENGTH,
     '#description' => t('Enter your @s username.', array('@s' => config('system.site')->get('name'))),
     '#required' => TRUE,
     '#attributes' => array(
@@ -1312,12 +1328,26 @@ function user_login_default_validators() {
 }
 
 /**
- * A FAPI validate handler. Sets an error if supplied username has been blocked.
+ * A FAPI validate handler. Depending on user_login_method, delegates
+ * validation to user_login_username_validate() and valid_email_address().
  */
 function user_login_name_validate($form, &$form_state) {
-  if (isset($form_state['values']['name']) && user_is_blocked($form_state['values']['name'])) {
-    // 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'])));
+  if (isset($form_state['values']['name'])) {
+    $name = $form_state['values']['name'];
+    $credentials = config('user.settings')->get('user_login_method');
+    if ($credentials != USER_LOGIN_USERNAME_ONLY) {
+      if ($account = db_query("SELECT * FROM {users} WHERE mail = :mail", array(':mail' => $name))->fetchObject()) {
+        $name = $account->name;
+      }
+      // If can't find account, check if valid email address.
+      elseif ($credentials == USER_LOGIN_EMAIL_ONLY && !valid_email_address($name)) {
+        form_set_error('name', t('The e-mail address %email is not valid.', array('%email' => $form_state['values']['name'])));
+      }
+    }
+    // If can find account, check if user is blocked.
+    if ($name && user_is_blocked($name)) {
+      form_set_error('name', t('The username %name has not been activated or is blocked.', array('%name' => $form_state['values']['name'])));
+    }
   }
 }
 
@@ -1339,7 +1369,15 @@ 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 = FALSE;
+    $credentials = config('user.settings')->get('user_login_method');
+    if ($credentials != USER_LOGIN_USERNAME_ONLY && valid_email_address($form_state['values']['name'])) {
+      $account = db_query("SELECT * FROM {users} WHERE mail = :mail AND status = 1", array(':mail' => $form_state['values']['name']))->fetchObject();
+    }
+    if (!$account && $credentials != USER_LOGIN_EMAIL_ONLY) {
+      $account = db_query("SELECT * FROM {users} WHERE name = :name AND status = 1", array(':name' => $form_state['values']['name']))->fetchObject();
+    }
+
     if ($account) {
       if ($flood_config->get('uid_only')) {
         // Register flood events based on the uid only, so they apply for any
@@ -1360,10 +1398,10 @@ function user_login_authenticate_validate($form, &$form_state) {
         $form_state['flood_control_triggered'] = 'user';
         return;
       }
+      // 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($account->name, $password);
     }
-    // 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);
   }
 }
 
@@ -1394,7 +1432,17 @@ function user_login_final_validate($form, &$form_state) {
       }
     }
     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'))));
+      switch (config('user.settings')->get('user_login_method')) {
+        case USER_LOGIN_USERNAME_ONLY:
+          form_set_error('name', t('Sorry, unrecognized username or password. <a href="@password">Have you forgotten your password?</a>', array('@password' => url('user/password'))));
+          break;
+        case USER_LOGIN_EMAIL_ONLY:
+          form_set_error('name', t('Sorry, unrecognized e-mail address or password. <a href="@password">Have you forgotten your password?</a>', array('@password' => url('user/password'))));
+          break;
+        case USER_LOGIN_USERNAME_OR_EMAIL:
+          form_set_error('name', t('Sorry, unrecognized username, e-mail address or password. <a href="@password">Have you forgotten your password?</a>', array('@password' => url('user/password'))));
+        break;
+      }
       watchdog('user', 'Login attempt failed for %user.', array('%user' => $form_state['values']['name']));
     }
   }
