diff --git a/core/modules/block/block.admin.inc b/core/modules/block/block.admin.inc
index 2a17a55..7a3c924 100644
--- a/core/modules/block/block.admin.inc
+++ b/core/modules/block/block.admin.inc
@@ -465,7 +465,7 @@ function block_admin_configure($form, &$form_state, $module, $delta) {
     ':module' => $block->module,
     ':delta' => $block->delta,
   ))->fetchCol();
-  $role_options = array_map('check_plain', user_roles());
+  $role_options = array_map('check_plain', user_role_names());
   $form['visibility']['role'] = array(
     '#type' => 'fieldset',
     '#title' => t('Roles'),
diff --git a/core/modules/comment/lib/Drupal/comment/Tests/CommentLinksTest.php b/core/modules/comment/lib/Drupal/comment/Tests/CommentLinksTest.php
index e1dcbec..8dbdd17 100644
--- a/core/modules/comment/lib/Drupal/comment/Tests/CommentLinksTest.php
+++ b/core/modules/comment/lib/Drupal/comment/Tests/CommentLinksTest.php
@@ -39,7 +39,7 @@ function testCommentLinks() {
 
     // Remove additional user permissions from $this->web_user added by setUp(),
     // since this test is limited to anonymous and authenticated roles only.
-    user_role_delete(key($this->web_user->roles));
+    entity_delete_multiple('user_role', array(key($this->web_user->roles)));
 
     // Matrix of possible environmental conditions and configuration settings.
     // See setEnvironment() for details.
diff --git a/core/modules/filter/filter.admin.inc b/core/modules/filter/filter.admin.inc
index 4f56856..0b4df2e 100644
--- a/core/modules/filter/filter.admin.inc
+++ b/core/modules/filter/filter.admin.inc
@@ -190,7 +190,7 @@ function filter_admin_format_form($form, &$form_state, $format) {
   $form['roles'] = array(
     '#type' => 'checkboxes',
     '#title' => t('Roles'),
-    '#options' => array_map('check_plain', user_roles()),
+    '#options' => array_map('check_plain', user_role_names()),
     '#disabled' => $is_fallback,
   );
   if ($is_fallback) {
diff --git a/core/modules/filter/filter.module b/core/modules/filter/filter.module
index b55066f..0d1c0d6 100644
--- a/core/modules/filter/filter.module
+++ b/core/modules/filter/filter.module
@@ -505,11 +505,11 @@ function filter_formats_reset() {
 function filter_get_roles_by_format($format) {
   // Handle the fallback format upfront (all roles have access to this format).
   if ($format->format == filter_fallback_format()) {
-    return user_roles();
+    return user_role_names();
   }
   // Do not list any roles if the permission does not exist.
   $permission = filter_permission_name($format);
-  return !empty($permission) ? user_roles(FALSE, $permission) : array();
+  return !empty($permission) ? user_role_names(FALSE, $permission) : array();
 }
 
 /**
diff --git a/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php b/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php
index f9bc3f4..ae03e52 100644
--- a/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php
+++ b/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php
@@ -475,10 +475,11 @@ protected function drupalCreateRole(array $permissions, $rid = NULL, $name = NUL
     }
 
     // Create new role.
-    $role = new stdClass();
-    $role->rid = $rid;
-    $role->name = $name;
-    $result = user_role_save($role);
+    $role = entity_create('user_role', array(
+      'rid' => $rid,
+      'name' => $name,
+    ));
+    $result = $role->save();
 
     $this->assertIdentical($result, SAVED_NEW, t('Created role ID @rid with name @name.', array(
       '@name' => var_export($role->name, TRUE),
diff --git a/core/modules/user/config/user.role.anonymous.yml b/core/modules/user/config/user.role.anonymous.yml
new file mode 100644
index 0000000..6b3f713
--- /dev/null
+++ b/core/modules/user/config/user.role.anonymous.yml
@@ -0,0 +1,3 @@
+rid: anonymous
+name: Anonymous user
+weight: 0
diff --git a/core/modules/user/config/user.role.authenticated.yml b/core/modules/user/config/user.role.authenticated.yml
new file mode 100644
index 0000000..1375647
--- /dev/null
+++ b/core/modules/user/config/user.role.authenticated.yml
@@ -0,0 +1,3 @@
+rid: authenticated
+name: Authenticated user
+weight: 1
diff --git a/core/modules/user/lib/Drupal/user/AccountFormController.php b/core/modules/user/lib/Drupal/user/AccountFormController.php
index b79e983..c38b7c0 100644
--- a/core/modules/user/lib/Drupal/user/AccountFormController.php
+++ b/core/modules/user/lib/Drupal/user/AccountFormController.php
@@ -126,7 +126,7 @@ public function form(array $form, array &$form_state, EntityInterface $account)
       '#access' => $admin,
     );
 
-    $roles = array_map('check_plain', user_roles(TRUE));
+    $roles = array_map('check_plain', user_role_names(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
diff --git a/core/modules/user/lib/Drupal/user/Plugin/views/access/Role.php b/core/modules/user/lib/Drupal/user/Plugin/views/access/Role.php
index 2a07d79..146968a 100644
--- a/core/modules/user/lib/Drupal/user/Plugin/views/access/Role.php
+++ b/core/modules/user/lib/Drupal/user/Plugin/views/access/Role.php
@@ -46,7 +46,7 @@ public function summaryTitle() {
       return t('Multiple roles');
     }
     else {
-      $rids = user_roles();
+      $rids = user_role_names();
       $rid = reset($this->options['role']);
       return check_plain($rids[$rid]);
     }
diff --git a/core/modules/user/lib/Drupal/user/Plugin/views/argument_validator/User.php b/core/modules/user/lib/Drupal/user/Plugin/views/argument_validator/User.php
index a31b0af..36a6a5a 100644
--- a/core/modules/user/lib/Drupal/user/Plugin/views/argument_validator/User.php
+++ b/core/modules/user/lib/Drupal/user/Plugin/views/argument_validator/User.php
@@ -56,7 +56,7 @@ public function buildOptionsForm(&$form, &$form_state) {
     $form['roles'] = array(
       '#type' => 'checkboxes',
       '#title' => t('Restrict to the selected roles'),
-      '#options' => array_map('check_plain', user_roles(TRUE)),
+      '#options' => array_map('check_plain', user_role_names(TRUE)),
       '#default_value' => $this->options['roles'],
       '#description' => t('If no roles are selected, users from any role will be allowed.'),
       '#states' => array(
diff --git a/core/modules/user/lib/Drupal/user/Plugin/views/filter/Roles.php b/core/modules/user/lib/Drupal/user/Plugin/views/filter/Roles.php
index 8ee3569..139856e 100644
--- a/core/modules/user/lib/Drupal/user/Plugin/views/filter/Roles.php
+++ b/core/modules/user/lib/Drupal/user/Plugin/views/filter/Roles.php
@@ -23,7 +23,7 @@
 class Roles extends ManyToOne {
 
   function get_value_options() {
-    $this->value_options = user_roles(TRUE);
+    $this->value_options = user_role_names(TRUE);
     unset($this->value_options[DRUPAL_AUTHENTICATED_RID]);
   }
 
diff --git a/core/modules/user/lib/Drupal/user/Tests/UserRoleAdminTest.php b/core/modules/user/lib/Drupal/user/Tests/UserRoleAdminTest.php
index 50d4da7..cc143ff 100644
--- a/core/modules/user/lib/Drupal/user/Tests/UserRoleAdminTest.php
+++ b/core/modules/user/lib/Drupal/user/Tests/UserRoleAdminTest.php
@@ -40,7 +40,7 @@ function testRoleAdministration() {
     $edit = array('role[name]' => $role_name, 'role[rid]' => $role_name);
     $this->drupalPost('admin/people/roles', $edit, t('Add role'));
     $this->assertText(t('The role has been added.'), 'The role has been added.');
-    $role = user_role_load($role_name);
+    $role = entity_load('user_role', $role_name);
     $this->assertTrue(is_object($role), 'The role was successfully retrieved from the database.');
 
     // Try adding a duplicate role.
@@ -53,7 +53,7 @@ function testRoleAdministration() {
     $edit = array('role[name]' => $role_name);
     $this->drupalPost("admin/people/roles/edit/{$role->rid}", $edit, t('Save role'));
     $this->assertText(t('The role has been renamed.'), 'The role has been renamed.');
-    $new_role = user_role_load($old_name);
+    $new_role = entity_load('user_role', $old_name);
     $this->assertEqual($new_role->name, $role_name, 'The role name has been successfully changed.');
 
     // Test deleting a role.
@@ -61,7 +61,7 @@ function testRoleAdministration() {
     $this->drupalPost(NULL, NULL, t('Delete'));
     $this->assertText(t('The role has been deleted.'), 'The role has been deleted');
     $this->assertNoLinkByHref("admin/people/roles/edit/{$role->rid}", 'Role edit link removed.');
-    $this->assertFalse(user_role_load($role_name), 'A deleted role can no longer be loaded.');
+    $this->assertFalse(entity_load('user_role', $role_name), 'A deleted role can no longer be loaded.');
 
     // Make sure that the system-defined roles can be edited via the user
     // interface.
@@ -80,8 +80,8 @@ function testRoleWeightChange() {
     $this->drupalLogin($this->admin_user);
 
     // Pick up a random role and get its weight.
-    $rid = array_rand(user_roles());
-    $role = user_role_load($rid);
+    $rid = array_rand(user_role_names());
+    $role = entity_load('user_role', $rid);
     $old_weight = $role->weight;
 
     // Change the role weight and submit the form.
@@ -90,7 +90,7 @@ function testRoleWeightChange() {
     $this->assertText(t('The role settings have been updated.'), 'The role settings form submitted successfully.');
 
     // Retrieve the saved role and compare its weight.
-    $role = user_role_load($rid);
+    $role = entity_load('user_role', $rid);
     $new_weight = $role->weight;
     $this->assertTrue(($old_weight + 1) == $new_weight, 'Role weight updated successfully.');
   }
diff --git a/core/modules/user/lib/Drupal/user/UserRole.php b/core/modules/user/lib/Drupal/user/UserRole.php
new file mode 100644
index 0000000..dd44ed2
--- /dev/null
+++ b/core/modules/user/lib/Drupal/user/UserRole.php
@@ -0,0 +1,52 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\user\UserRole.
+ */
+
+namespace Drupal\user;
+
+use Drupal\Core\Config\Entity\ConfigEntityBase;
+
+/**
+ * Defines the user role entity.
+ */
+class UserRole extends ConfigEntityBase {
+
+  /**
+   * The primary identifier of a role (config name).
+   *
+   * @var string
+   */
+  public $rid;
+
+  /**
+   * The UUID of a role.
+   *
+   * @var string
+   */
+  public $uuid;
+
+  /**
+   * The label of a role.
+   *
+   * @var string
+   */
+  public $name;
+
+  /**
+   * The weight of this role in listings and the user interface.
+   *
+   * @var int
+   */
+  public $weight = 0;
+
+  /**
+   * Overrides Entity::id().
+   */
+  public function id() {
+    return $this->rid;
+  }
+
+}
diff --git a/core/modules/user/lib/Drupal/user/UserRoleStorageController.php b/core/modules/user/lib/Drupal/user/UserRoleStorageController.php
new file mode 100644
index 0000000..b673c94
--- /dev/null
+++ b/core/modules/user/lib/Drupal/user/UserRoleStorageController.php
@@ -0,0 +1,76 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\user\UserRoleStorageController.
+ */
+
+namespace Drupal\user;
+
+use Drupal\Core\Config\Entity\ConfigStorageController;
+use Drupal\Core\Entity\EntityInterface;
+
+/**
+ * Controller class for user roles.
+ *
+ * This extends the Drupal\Core\Entity\ConfigStorageController class, adding
+ * required special handling for user role objects.
+ */
+class UserRoleStorageController extends ConfigStorageController {
+
+  /**
+   * Overrides Drupal\Core\Entity\ConfigStorageController::save().
+   */
+  public function save(EntityInterface $entity) {
+    // Prevent leading and trailing spaces in role names.
+    $entity->name = trim($entity->name);
+
+    if (!isset($entity->weight)) {
+      $roles = entity_load_multiple('entity_roles');
+      // Set a role weight to make this new role last.
+      $max = array_reduce($roles, function($max, $entity) {
+        return $max > $entity['weight'] ? $max : $entity['weight'];
+      });
+      $entity->weight = $max + 1;
+    }
+
+    return parent::save($entity);
+  }
+
+  /**
+   * Overrides Drupal\Core\Entity\ConfigStorageController::resetCache().
+   */
+  public function resetCache(array $ids = NULL) {
+    parent::resetCache($ids);
+
+    // Clear the user access cache.
+    drupal_static_reset('user_access');
+    drupal_static_reset('user_role_permissions');
+  }
+
+  /**
+   * Overrides Drupal\Core\Entity\ConfigStorageController::postDelete().
+   */
+  protected function postDelete($entities) {
+    $rids = array_keys($entities);
+
+    db_delete('role_permission')
+      ->condition('rid', $rids)
+      ->execute();
+    // Update the users who have this role set:
+    db_delete('users_roles')
+      ->condition('rid', $rids)
+      ->execute();
+  }
+
+  /**
+   * Overrides Drupal\Core\Entity\ConfigStorageController::attachLoad().
+   */
+  protected function attachLoad(&$queried_entities, $revision_id = FALSE) {
+    // Sort the queried roles by their weight.
+    uasort($queried_entities, 'drupal_sort_weight');
+
+    parent::attachLoad($queried_entities, $revision_id);
+  }
+
+}
diff --git a/core/modules/user/lib/Drupal/user/UserStorageController.php b/core/modules/user/lib/Drupal/user/UserStorageController.php
index 5f340e4..4f9c528 100644
--- a/core/modules/user/lib/Drupal/user/UserStorageController.php
+++ b/core/modules/user/lib/Drupal/user/UserStorageController.php
@@ -40,9 +40,9 @@ function attachLoad(&$queried_users, $load_revision = FALSE) {
     }
 
     // Add any additional roles from the database.
-    $result = db_query('SELECT r.rid, r.name, ur.uid FROM {role} r INNER JOIN {users_roles} ur ON ur.rid = r.rid WHERE ur.uid IN (:uids)', array(':uids' => array_keys($queried_users)));
+    $result = db_query('SELECT ur.rid, ur.uid FROM {users_roles} ur WHERE ur.uid IN (:uids)', array(':uids' => array_keys($queried_users)));
     foreach ($result as $record) {
-      $queried_users[$record->uid]->roles[$record->rid] = $record->name;
+      $queried_users[$record->uid]->roles[$record->rid] = $record->rid;
     }
 
     // Add the full file objects for user pictures if enabled.
diff --git a/core/modules/user/user.admin.inc b/core/modules/user/user.admin.inc
index 396f4c0..031df3f 100644
--- a/core/modules/user/user.admin.inc
+++ b/core/modules/user/user.admin.inc
@@ -194,7 +194,7 @@ function user_admin_account() {
   $destination = drupal_get_destination();
 
   $status = array(t('blocked'), t('active'));
-  $roles = array_map('check_plain', user_roles(TRUE));
+  $roles = array_map('check_plain', user_role_names(TRUE));
   $accounts = array();
   foreach ($result as $account) {
     $users_roles = array();
@@ -294,7 +294,7 @@ function user_admin_settings($form, &$form_state) {
 
   // Do not allow users to set the anonymous or authenticated user roles as the
   // administrator role.
-  $roles = user_roles();
+  $roles = user_role_names();
   unset($roles[DRUPAL_ANONYMOUS_RID]);
   unset($roles[DRUPAL_AUTHENTICATED_RID]);
   $roles[0] = t('disabled');
@@ -699,7 +699,7 @@ function user_admin_settings_submit($form, &$form_state) {
 function user_admin_permissions($form, $form_state, $rid = NULL) {
 
   // Retrieve role names for columns.
-  $role_names = user_roles();
+  $role_names = user_role_names();
   if (isset($rid)) {
     $role_names = array($rid => $role_names[$rid]);
   }
@@ -800,7 +800,7 @@ function user_admin_permissions_submit($form, &$form_state) {
 function theme_user_admin_permissions($variables) {
   $form = $variables['form'];
 
-  $roles = user_roles();
+  $roles = user_role_names();
   foreach (element_children($form['permission']) as $key) {
     $row = array();
     // Module name
@@ -869,12 +869,7 @@ function theme_user_permission_description($variables) {
  * @see theme_user_admin_roles()
  */
 function user_admin_roles($form, $form_state) {
-  $roles = db_select('role', 'r')
-    ->addTag('translatable')
-    ->fields('r')
-    ->orderBy('weight')
-    ->orderBy('name')
-    ->execute();
+  $roles = user_roles();
 
   $form['roles'] = array(
     '#tree' => TRUE,
@@ -942,7 +937,7 @@ function user_admin_roles_order_submit($form, &$form_state) {
   foreach ($form_state['values']['roles'] as $rid => $role_values) {
     $role = $form['roles'][$rid]['#role'];
     $role->weight = $role_values['weight'];
-    user_role_save($role);
+    $role->save();
   }
   drupal_set_message(t('The role settings have been updated.'));
 }
@@ -1047,8 +1042,8 @@ function user_admin_role($form, $form_state, $role) {
  * Form submit handler for the user_admin_role() form.
  */
 function user_admin_role_submit($form, &$form_state) {
-  $role = (object) $form_state['values']['role'];
-  $status = user_role_save($role);
+  $role = entity_create('user_role', $form_state['values']['role']);
+  $status = $role->save();
   if ($status === SAVED_UPDATED) {
     drupal_set_message(t('The role has been renamed.'));
   }
@@ -1080,7 +1075,7 @@ function user_admin_role_delete_confirm($form, &$form_state, $role) {
  * Form submit handler for user_admin_role_delete_confirm().
  */
 function user_admin_role_delete_confirm_submit($form, &$form_state) {
-  user_role_delete($form_state['values']['rid']);
+  entity_delete_multiple('user_role', array($form_state['values']['rid']));
   drupal_set_message(t('The role has been deleted.'));
   $form_state['redirect'] = 'admin/people/roles';
 }
diff --git a/core/modules/user/user.install b/core/modules/user/user.install
index 492f1e0..e2f32a6 100644
--- a/core/modules/user/user.install
+++ b/core/modules/user/user.install
@@ -203,39 +203,6 @@ function user_schema() {
     ),
   );
 
-  $schema['role'] = array(
-    'description' => 'Stores user roles.',
-    'fields' => array(
-      'rid' => array(
-        'type' => 'varchar',
-        // The role ID is often used as part of a compound index; at least MySQL
-        // has a maximum index length of 1000 characters (333 on utf8), so we
-        // limit the maximum length.
-        'length' => 64,
-        'not null' => TRUE,
-        'description' => 'Primary Key: Unique role ID.',
-      ),
-      'name' => array(
-        'type' => 'varchar',
-        'length' => 255,
-        'not null' => TRUE,
-        'default' => '',
-        'description' => 'Role label.',
-        'translatable' => TRUE,
-      ),
-      'weight' => array(
-        'type' => 'int',
-        'not null' => TRUE,
-        'default' => 0,
-        'description' => 'The weight of this role in listings and the user interface.',
-      ),
-    ),
-    'primary key' => array('rid'),
-    'indexes' => array(
-      'name_weight' => array('name', 'weight'),
-    ),
-  );
-
   $schema['role_permission'] = array(
     'description' => 'Stores the permissions assigned to user roles.',
     'fields' => array(
@@ -334,13 +301,6 @@ function user_install() {
       'data' => NULL,
     ))
     ->execute();
-
-  // Insert built-in roles.
-  db_insert('role')
-    ->fields(array('rid', 'name', 'weight'))
-    ->values(array(DRUPAL_ANONYMOUS_RID, 'Anonymous user', 0))
-    ->values(array(DRUPAL_AUTHENTICATED_RID, 'Authenticated user', 1))
-    ->execute();
 }
 
 /**
@@ -599,5 +559,26 @@ function user_update_8009(&$sandbox) {
 }
 
 /**
+ * Replace the role table with configuration system as a backend for storing roles.
+ */
+function user_update_8010() {
+  $roles = db_select('role', 'r')->fields('r')
+    ->execute()->fetchAll();
+
+  entity_info_cache_clear();
+
+  foreach ($roles as $role) {
+    $entity = entity_create('user_role', array(
+      'rid' => $role->rid,
+      'name' => $role->name,
+      'weight' => $role->weight,
+    ));
+    $entity->save();
+  }
+
+  db_drop_table('role');
+}
+
+/**
  * @} End of "addtogroup updates-7.x-to-8.x".
  */
diff --git a/core/modules/user/user.module b/core/modules/user/user.module
index b7ac23d..8a59fe6 100644
--- a/core/modules/user/user.module
+++ b/core/modules/user/user.module
@@ -1,6 +1,7 @@
 <?php
 
 use Drupal\Core\Database\Query\SelectInterface;
+use Drupal\user\UserRole;
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\file\File;
 use Drupal\Core\Template\Attribute;
@@ -142,41 +143,53 @@ function user_theme() {
  * Implements hook_entity_info().
  */
 function user_entity_info() {
-  return array(
-    'user' => array(
-      'label' => t('User'),
-      'controller class' => 'Drupal\user\UserStorageController',
-      'form controller class' => array(
-        'profile' => 'Drupal\user\ProfileFormController',
-        'register' => 'Drupal\user\RegisterFormController',
-      ),
-      'base table' => 'users',
-      'uri callback' => 'user_uri',
-      'label callback' => 'user_label',
-      'fieldable' => TRUE,
-      'entity class' => 'Drupal\user\User',
-      'entity keys' => array(
-        'id' => 'uid',
-        'uuid' => 'uuid',
-      ),
-      'bundles' => array(
-        'user' => array(
-          'label' => t('User'),
-          'admin' => array(
-            'path' => 'admin/config/people/accounts',
-            'access arguments' => array('administer users'),
-          ),
+  $info['user'] = array(
+    'label' => t('User'),
+    'controller class' => 'Drupal\user\UserStorageController',
+    'form controller class' => array(
+      'profile' => 'Drupal\user\ProfileFormController',
+      'register' => 'Drupal\user\RegisterFormController',
+    ),
+    'base table' => 'users',
+    'uri callback' => 'user_uri',
+    'label callback' => 'user_label',
+    'fieldable' => TRUE,
+    'entity class' => 'Drupal\user\User',
+    'entity keys' => array(
+      'id' => 'uid',
+      'uuid' => 'uuid',
+    ),
+    'bundles' => array(
+      'user' => array(
+        'label' => t('User'),
+        'admin' => array(
+          'path' => 'admin/config/people/accounts',
+          'access arguments' => array('administer users'),
         ),
       ),
-      'render controller class' => 'Drupal\user\UserRenderController',
-      'view modes' => array(
-        'full' => array(
-          'label' => t('User account'),
-          'custom settings' => FALSE,
-        ),
+    ),
+    'render controller class' => 'Drupal\user\UserRenderController',
+    'view modes' => array(
+      'full' => array(
+        'label' => t('User account'),
+        'custom settings' => FALSE,
       ),
     ),
   );
+
+  $info['user_role'] = array(
+    'label' => t('User role'),
+    'entity class' => 'Drupal\user\UserRole',
+    'controller class' => 'Drupal\user\UserRoleStorageController',
+    'config prefix' => 'user.role',
+    'entity keys' => array(
+      'id' => 'rid',
+      'label' => 'name',
+      'uuid' => 'uuid',
+    ),
+  );
+
+  return $info;
 }
 
 /**
@@ -2147,6 +2160,25 @@ function user_mail_tokens(&$replacements, $data, $options) {
  *   An associative array with the role id as the key and the role name as
  *   value.
  */
+function user_role_names($membersonly = FALSE, $permission = NULL) {
+  return array_map(function($item) {
+    return $item->name;
+  }, user_roles($membersonly, $permission));
+}
+
+/**
+ * Retrieve an array of roles matching specified conditions.
+ *
+ * @param $membersonly
+ *   Set this to TRUE to exclude the 'anonymous' role.
+ * @param $permission
+ *   A string containing a permission. If set, only roles containing that
+ *   permission are returned.
+ *
+ * @return
+ *   An associative array with the role id as the key and the role object as
+ *   value.
+ */
 function user_roles($membersonly = FALSE, $permission = NULL) {
   $user_roles = &drupal_static(__FUNCTION__);
 
@@ -2159,23 +2191,21 @@ function user_roles($membersonly = FALSE, $permission = NULL) {
     }
   }
 
-  $query = db_select('role', 'r');
-  $query->addTag('translatable');
-  $query->fields('r', array('rid', 'name'));
-  $query->orderBy('weight');
-  $query->orderBy('name');
+  $roles = entity_load_multiple('user_role');
+  if ($membersonly) {
+    unset($roles[DRUPAL_ANONYMOUS_RID]);
+  }
+
   if (!empty($permission)) {
-    $query->innerJoin('role_permission', 'p', 'r.rid = p.rid');
+    $query = db_select('role_permission', 'p');
+    $query->fields('p', array('rid'));
     $query->condition('p.permission', $permission);
+    $rids = $query->execute()->fetchCol();
+    $roles = array_intersect_key($roles, array_keys($rids));
   }
-  if ($membersonly) {
-    $query->condition('r.rid', DRUPAL_ANONYMOUS_RID, '!=');
-  }
-  $roles = $query->execute()->fetchAllKeyed();
 
   if (empty($permission)) {
     $user_roles[$cid] = $roles;
-    return $user_roles[$cid];
   }
 
   return $roles;
@@ -2192,87 +2222,7 @@ function user_roles($membersonly = FALSE, $permission = NULL) {
  *   otherwise.
  */
 function user_role_load($rid) {
-  return db_select('role', 'r')
-    ->fields('r')
-    ->condition('rid', $rid)
-    ->execute()
-    ->fetchObject();
-}
-
-/**
- * Save a user role to the database.
- *
- * @param $role
- *   A role object to modify or add.
- *
- * @return
- *   Status constant indicating if role was created or updated.
- *   Failure to write the user role record will return FALSE. Otherwise
- *   SAVED_NEW or SAVED_UPDATED is returned depending on the operation
- *   performed.
- */
-function user_role_save($role) {
-  if ($role->name) {
-    // Prevent leading and trailing spaces in role names.
-    $role->name = trim($role->name);
-  }
-  if (!isset($role->weight)) {
-    // Set a role weight to make this new role last.
-    $query = db_select('role');
-    $query->addExpression('MAX(weight)');
-    $role->weight = $query->execute()->fetchField() + 1;
-  }
-
-  // Let modules modify the user role before it is saved to the database.
-  module_invoke_all('user_role_presave', $role);
-
-  $exists = db_select('role', 'r')
-    ->fields('r', array('rid'))
-    ->condition('rid', $role->rid)
-    ->execute()
-    ->fetchAll();
-
-  if (empty($exists)) {
-    $status = drupal_write_record('role', $role);
-    module_invoke_all('user_role_insert', $role);
-  }
-  else {
-    $status = drupal_write_record('role', $role, 'rid');
-    module_invoke_all('user_role_update', $role);
-  }
-
-  // Clear the user access cache.
-  drupal_static_reset('user_access');
-  drupal_static_reset('user_role_permissions');
-
-  return $status;
-}
-
-/**
- * Delete a user role from database.
- *
- * @param $role
- *   A string with the role ID.
- */
-function user_role_delete($role) {
-  $role = user_role_load($role);
-
-  db_delete('role')
-    ->condition('rid', $role->rid)
-    ->execute();
-  db_delete('role_permission')
-    ->condition('rid', $role->rid)
-    ->execute();
-  // Update the users who have this role set:
-  db_delete('users_roles')
-    ->condition('rid', $role->rid)
-    ->execute();
-
-  module_invoke_all('user_role_delete', $role);
-
-  // Clear the user access cache.
-  drupal_static_reset('user_access');
-  drupal_static_reset('user_role_permissions');
+  return entity_load('user_role', $rid);
 }
 
 /**
@@ -2419,7 +2369,7 @@ function user_user_operations($form = array(), $form_state = array()) {
   );
 
   if (user_access('administer permissions')) {
-    $roles = user_roles(TRUE);
+    $roles = user_role_names(TRUE);
     unset($roles[DRUPAL_AUTHENTICATED_RID]);  // Can't edit authenticated role.
 
     $add_roles = array();
@@ -2504,7 +2454,7 @@ function user_user_operations_block($accounts) {
  * Callback function for admin mass adding/deleting a user role.
  */
 function user_multiple_role_edit($accounts, $operation, $rid) {
-  $role_name = db_query('SELECT name FROM {role} WHERE rid = :rid', array(':rid' => $rid))->fetchField();
+  $role_name = entity_load('user_role', $rid)->name;
 
   switch ($operation) {
     case 'add_role':
@@ -2640,7 +2590,7 @@ function user_multiple_cancel_confirm_submit($form, &$form_state) {
 function user_filters() {
   // Regular filters
   $filters = array();
-  $roles = user_roles(TRUE);
+  $roles = user_role_names(TRUE);
   unset($roles[DRUPAL_AUTHENTICATED_RID]); // Don't list authorized role.
   if (count($roles)) {
     $filters['role'] = array(
diff --git a/core/modules/user/user.views.inc b/core/modules/user/user.views.inc
index 295278a..837e41d 100644
--- a/core/modules/user/user.views.inc
+++ b/core/modules/user/user.views.inc
@@ -378,7 +378,7 @@ function user_views_data() {
   );
 
   // role table
-
+  // @todo What do we do with this?
   $data['role']['table']['join'] = array(
      // Directly links to users table.
     'users' => array(
diff --git a/core/modules/views/lib/Drupal/views/Plugin/views/filter/FilterPluginBase.php b/core/modules/views/lib/Drupal/views/Plugin/views/filter/FilterPluginBase.php
index 6b32ca3..9a3a224 100644
--- a/core/modules/views/lib/Drupal/views/Plugin/views/filter/FilterPluginBase.php
+++ b/core/modules/views/lib/Drupal/views/Plugin/views/filter/FilterPluginBase.php
@@ -548,7 +548,7 @@ public function buildExposeForm(&$form, &$form_state) {
       '#default_value' => $this->options['expose']['remember'],
     );
 
-    $role_options = array_map('check_plain', user_roles());
+    $role_options = array_map('check_plain', user_role_names());
     $form['expose']['remember_roles'] = array(
       '#type' => 'checkboxes',
       '#title' => t('User roles'),
diff --git a/core/profiles/standard/standard.install b/core/profiles/standard/standard.install
index b4dc761..62945cd 100644
--- a/core/profiles/standard/standard.install
+++ b/core/profiles/standard/standard.install
@@ -379,11 +379,12 @@ function standard_install() {
   user_role_grant_permissions(DRUPAL_AUTHENTICATED_RID, array('access content', 'access comments', 'post comments', 'skip comment approval', $filtered_html_permission));
 
   // Create a default role for site administrators, with all available permissions assigned.
-  $admin_role = new stdClass();
-  $admin_role->rid = 'administrator';
-  $admin_role->name = 'Administrator';
-  $admin_role->weight = 2;
-  user_role_save($admin_role);
+  $admin_role = entity_create('user_role', array(
+    'rid' => 'administrator',
+    'name' => 'Administrator',
+    'weight' => 2,
+  ));
+  $admin_role->save();
   user_role_grant_permissions($admin_role->rid, array_keys(module_invoke_all('permission')));
   // Set this as the administrator role.
   $user_settings->set('admin_role', $admin_role->rid)->save();
