diff --git a/core/modules/block/block.admin.inc b/core/modules/block/block.admin.inc
index ffa0b0b..b9666f9 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' => 'details',
     '#title' => t('Roles'),
diff --git a/core/modules/comment/comment.module b/core/modules/comment/comment.module
index ab757a9..443ef08 100644
--- a/core/modules/comment/comment.module
+++ b/core/modules/comment/comment.module
@@ -1284,9 +1284,12 @@ function comment_node_update_index(Node $node, $langcode) {
   if ($index_comments === NULL) {
     // Find and save roles that can 'access comments' or 'search content'.
     $perms = array('access comments' => array(), 'search content' => array());
-    $result = db_query("SELECT rid, permission FROM {role_permission} WHERE permission IN ('access comments', 'search content')");
-    foreach ($result as $record) {
-      $perms[$record->permission][$record->rid] = $record->rid;
+    foreach (user_roles() as $role) {
+      foreach ($perms as $permission => $roles) {
+        if (array_key_exists($permission, $role->permissions)) {
+          $perms[$permission][$role->rid] = $role->rid;
+        }
+      }
     }
 
     // Prevent indexing of comments if there are any roles that can search but
diff --git a/core/modules/comment/lib/Drupal/comment/Tests/CommentLinksTest.php b/core/modules/comment/lib/Drupal/comment/Tests/CommentLinksTest.php
index d049aa3..91cab48 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 c01fb93..0b75ba0 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 1aff070..632edde 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/filter/lib/Drupal/filter/Tests/FilterFormatAccessTest.php b/core/modules/filter/lib/Drupal/filter/Tests/FilterFormatAccessTest.php
index 4636610..9c2fd68 100644
--- a/core/modules/filter/lib/Drupal/filter/Tests/FilterFormatAccessTest.php
+++ b/core/modules/filter/lib/Drupal/filter/Tests/FilterFormatAccessTest.php
@@ -147,7 +147,7 @@ function testFormatRoles() {
     $this->assertFalse(in_array($this->disallowed_format->format, array_keys(filter_get_formats_by_role($rid))), 'A text format which a role does not have access to does not appear in the list of formats available to that role.');
 
     // Check that the fallback format is always allowed.
-    $this->assertEqual(filter_get_roles_by_format(filter_format_load(filter_fallback_format())), user_roles(), 'All roles have access to the fallback format.');
+    $this->assertEqual(filter_get_roles_by_format(filter_format_load(filter_fallback_format())), user_role_names(), 'All roles have access to the fallback format.');
     $this->assertTrue(in_array(filter_fallback_format(), array_keys(filter_get_formats_by_role($rid))), 'The fallback format appears in the list of allowed formats for any role.');
   }
 
diff --git a/core/modules/node/lib/Drupal/node/Tests/NodeAccessLanguageTest.php b/core/modules/node/lib/Drupal/node/Tests/NodeAccessLanguageTest.php
index 6ff6ae0..8c250a6 100644
--- a/core/modules/node/lib/Drupal/node/Tests/NodeAccessLanguageTest.php
+++ b/core/modules/node/lib/Drupal/node/Tests/NodeAccessLanguageTest.php
@@ -41,11 +41,10 @@ function assertNodeAccess($ops, $node, $account, $langcode = NULL) {
 
   function setUp() {
     parent::setUp();
-
     // Clear permissions for authenticated users.
-    db_delete('role_permission')
-      ->condition('rid', DRUPAL_AUTHENTICATED_RID)
-      ->execute();
+    $role = entity_load('user_role', DRUPAL_AUTHENTICATED_RID);
+    $role->permissions = array();
+    $role->save();
   }
 
   /**
diff --git a/core/modules/node/lib/Drupal/node/Tests/NodeAccessTest.php b/core/modules/node/lib/Drupal/node/Tests/NodeAccessTest.php
index 4f87348..4e6f2a1 100644
--- a/core/modules/node/lib/Drupal/node/Tests/NodeAccessTest.php
+++ b/core/modules/node/lib/Drupal/node/Tests/NodeAccessTest.php
@@ -36,9 +36,9 @@ function assertNodeAccess($ops, $node, $account) {
   function setUp() {
     parent::setUp();
     // Clear permissions for authenticated users.
-    db_delete('role_permission')
-      ->condition('rid', DRUPAL_AUTHENTICATED_RID)
-      ->execute();
+    $role = entity_load('user_role', DRUPAL_AUTHENTICATED_RID);
+    $role->permissions = array();
+    $role->save();
   }
 
   /**
diff --git a/core/modules/node/node.views.inc b/core/modules/node/node.views.inc
index a67b870..f159e39 100644
--- a/core/modules/node/node.views.inc
+++ b/core/modules/node/node.views.inc
@@ -690,20 +690,11 @@ function node_views_analyze($view) {
         // check for no access control
         $access = $display->getOption('access');
         if (empty($access['type']) || $access['type'] == 'none') {
-          $select = db_select('role', 'r');
-          $select->innerJoin('role_permission', 'p', 'r.rid = p.rid');
-          $result = $select->fields('r', array('rid'))
-            ->fields('p', array('permission'))
-            ->condition('r.rid', array('anonymous', 'authenticated'), 'IN')
-            ->condition('p.permission', 'access content')
-            ->execute();
-
-          foreach ($result as $role) {
-            $role->safe = TRUE;
-            $roles[$role->rid] = $role;
-          }
-          if (!($roles['anonymous']->safe && $roles['authenticated']->safe)) {
-            $ret[] = Analyzer::formatMessage(t('Some roles lack permission to access content, but display %display has no access control.', array('%display' => $display['display_title'])), 'warning');
+          // Find out whether anonymous and authenticated role have the
+          // 'access content' permission.
+          $roles = user_roles(FALSE, 'access content');
+          if (!isset($roles[DRUPAL_ANONYMOUS_RID]) && !isset($roles[DRUPAL_AUTHENTICATED_RID])) {
+            $ret[] = Analyzer::formatMessage(t('Some roles lack permission to access content, but display %display has no access control.', array('%display' => $display->display['display_title'])), 'warning');
           }
           $filters = $display->getOption('filters');
           foreach ($filters as $filter) {
diff --git a/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php b/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php
index 001e521..6a5e4fc 100644
--- a/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php
+++ b/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php
@@ -481,10 +481,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),
@@ -496,8 +497,8 @@ protected function drupalCreateRole(array $permissions, $rid = NULL, $name = NUL
       if (!empty($permissions)) {
         user_role_grant_permissions($role->rid, $permissions);
 
-        $assigned_permissions = db_query('SELECT permission FROM {role_permission} WHERE rid = :rid', array(':rid' => $role->rid))->fetchCol();
-        $missing_permissions = array_diff($permissions, $assigned_permissions);
+        $roles = user_roles();
+        $missing_permissions = array_diff($permissions, array_keys($roles[$role->rid]->permissions));
         if (!$missing_permissions) {
           $this->pass(t('Created permissions: @perms', array('@perms' => implode(', ', $permissions))), t('Role'));
         }
diff --git a/core/modules/system/lib/Drupal/system/Tests/Module/UninstallTest.php b/core/modules/system/lib/Drupal/system/Tests/Module/UninstallTest.php
index 3345d2f..a710435 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Module/UninstallTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Module/UninstallTest.php
@@ -38,8 +38,7 @@ function testUserPermsUninstalled() {
     module_disable(array('module_test'));
     module_uninstall(array('module_test'));
 
-    // Are the perms defined by module_test removed from {role_permission}.
-    $count = db_query("SELECT COUNT(rid) FROM {role_permission} WHERE permission = :perm", array(':perm' => 'module_test perm'))->fetchField();
-    $this->assertEqual(0, $count, 'Permissions were all removed.');
+    // Are the perms defined by module_test removed.
+    $this->assertFalse(user_roles(FALSE, 'module_test perm'), 'Permissions were all removed.');
   }
 }
diff --git a/core/modules/system/lib/Drupal/system/Tests/Upgrade/LanguageUpgradePathTest.php b/core/modules/system/lib/Drupal/system/Tests/Upgrade/LanguageUpgradePathTest.php
index 73f563b..284b866 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Upgrade/LanguageUpgradePathTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Upgrade/LanguageUpgradePathTest.php
@@ -178,11 +178,10 @@ public function testLanguagePermissionsUpgrade() {
 
     $this->assertTrue($this->performUpgrade(), 'The upgrade was completed successfully.');
 
+    $roles = user_roles();
     // Check that translate content role doesn't exist on database.
-    $old_permission_exists = db_query('SELECT * FROM {role_permission} WHERE permission LIKE ?', array('translate content'))->fetchObject();
-    $this->assertFalse($old_permission_exists, 'No translate content role left on database.');
+    $this->assertFalse(array_key_exists('translate content', $roles[DRUPAL_AUTHENTICATED_RID]->permissions), 'No translate content role left on database.');
     // Check that translate content has been renamed to translate all content.
-    $new_permission_exists = db_query('SELECT * FROM {role_permission} WHERE permission LIKE ?', array('translate all content'))->fetchObject();
-    $this->assertTrue($new_permission_exists, 'Rename role translate content to translate all content was completed successfully.');
+    $this->assertTrue(array_key_exists('translate all content', $roles[DRUPAL_AUTHENTICATED_RID]->permissions), 'Rename role translate content to translate all content was completed successfully.');
   }
 }
diff --git a/core/modules/translation/translation.install b/core/modules/translation/translation.install
index 61d014d..2d9463a 100644
--- a/core/modules/translation/translation.install
+++ b/core/modules/translation/translation.install
@@ -10,10 +10,14 @@
  * Rename the translate content permission.
  */
 function translation_update_8000() {
-  db_update('role_permission')
-    ->fields(array('permission' => 'translate all content'))
-    ->condition('permission', 'translate content')
-    ->execute();
+  foreach (config_get_storage_names_with_prefix('user.role.') as $name) {
+    $role = config($name)->get();
+    if (array_key_exists('translate content', $role['permissions'])) {
+      unset($role['permissions']['translate content']);
+      $role['permissions']['translate all content'] = 'translate all content';
+      config($name)->setData($role)->save();
+    }
+  }
 }
 
 /**
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 512f703..b3043de 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/Core/Entity/Role.php b/core/modules/user/lib/Drupal/user/Plugin/Core/Entity/Role.php
new file mode 100644
index 0000000..3cd550b
--- /dev/null
+++ b/core/modules/user/lib/Drupal/user/Plugin/Core/Entity/Role.php
@@ -0,0 +1,74 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\user\Plugin\Core\Entity\Role.
+ */
+
+namespace Drupal\user\Plugin\Core\Entity;
+
+use Drupal\Core\Annotation\Plugin;
+use Drupal\Core\Annotation\Translation;
+use Drupal\Core\Config\Entity\ConfigEntityBase;
+
+/**
+ * Defines the user role entity class.
+ *
+ * @Plugin(
+ *   id = "user_role",
+ *   label = @Translation("Role"),
+ *   module = "user",
+ *   controller_class = "Drupal\user\RoleStorageController",
+ *   config_prefix = "user.role",
+ *   entity_keys = {
+ *     "id" = "rid",
+ *     "uuid" = "uuid",
+ *     "label" = "name"
+ *   }
+ * )
+ */
+class Role 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 permissions of a role.
+   *
+   * @var array
+   */
+  public $permissions = array();
+
+  /**
+   * 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/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/RolesRid.php b/core/modules/user/lib/Drupal/user/Plugin/views/argument/RolesRid.php
index 634307e..1d18b0b 100644
--- a/core/modules/user/lib/Drupal/user/Plugin/views/argument/RolesRid.php
+++ b/core/modules/user/lib/Drupal/user/Plugin/views/argument/RolesRid.php
@@ -23,16 +23,7 @@
 class RolesRid extends ManyToOne {
 
   function title_query() {
-    $titles = array();
-
-    $query = db_select('role', 'r');
-    $query->addField('r', 'name');
-    $query->condition('r.rid', $this->value);
-    $result = $query->execute();
-    foreach ($result as $term) {
-      $titles[] = check_plain($term->name);
-    }
-    return $titles;
+    return array(entity_load('user_role', $this->value)->name);
   }
 
 }
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/field/Permissions.php b/core/modules/user/lib/Drupal/user/Plugin/views/field/Permissions.php
index 98cb021..5e1cb34 100644
--- a/core/modules/user/lib/Drupal/user/Plugin/views/field/Permissions.php
+++ b/core/modules/user/lib/Drupal/user/Plugin/views/field/Permissions.php
@@ -46,28 +46,19 @@ function pre_render(&$values) {
     }
 
     if ($uids) {
-      // Get a list of all the modules implementing a hook_permission() and sort by
-      // display name.
-      $module_info = system_get_info('module');
-      $modules = array();
-      foreach (module_implements('permission') as $module) {
-        $modules[$module] = $module_info[$module]['name'];
-      }
-      asort($modules);
-
-      $permissions = module_invoke_all('permission');
-
-      $query = db_select('role_permission', 'rp');
-      $query->join('users_roles', 'u', 'u.rid = rp.rid');
-      $query->fields('u', array('uid', 'rid'));
-      $query->addField('rp', 'permission');
-      $query->condition('u.uid', $uids);
-      $query->condition('rp.module', array_keys($modules));
-      $query->orderBy('rp.permission');
-      $result = $query->execute();
-
-      foreach ($result as $perm) {
-        $this->items[$perm->uid][$perm->permission]['permission'] = $permissions[$perm->permission]['title'];
+      // Load all permissions to be able show the label.
+      $all_permissions = module_invoke_all('permission');
+      $roles = user_roles();
+
+      foreach ($values as $row) {
+        $account = $this->get_entity($row);
+        // Get a list of roles of all the users to load all permissions of each
+        // user.
+        foreach ($roles as $role) {
+          foreach ($role->permissions as $permission => $value) {
+            $this->items[$account->uid][$permission]['permission'] = $all_permissions[$permission]['title'];
+          }
+        }
       }
     }
   }
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/RoleStorageController.php b/core/modules/user/lib/Drupal/user/RoleStorageController.php
new file mode 100644
index 0000000..225bcf9
--- /dev/null
+++ b/core/modules/user/lib/Drupal/user/RoleStorageController.php
@@ -0,0 +1,71 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\user\RoleStorageController.
+ */
+
+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 RoleStorageController 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_roles');
+  }
+
+  /**
+   * Overrides Drupal\Core\Entity\ConfigStorageController::postDelete().
+   */
+  protected function postDelete($entities) {
+    // Update the users who have this role set:
+    db_delete('users_roles')
+      ->condition('rid', array_keys($entities))
+      ->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\Core\Config\Entity\ConfigEntityBase::sort');
+
+    parent::attachLoad($queried_entities, $revision_id);
+  }
+
+}
diff --git a/core/modules/user/lib/Drupal/user/Tests/UserPermissionsTest.php b/core/modules/user/lib/Drupal/user/Tests/UserPermissionsTest.php
index 2455b10..9f75a7d 100644
--- a/core/modules/user/lib/Drupal/user/Tests/UserPermissionsTest.php
+++ b/core/modules/user/lib/Drupal/user/Tests/UserPermissionsTest.php
@@ -47,7 +47,7 @@ function testUserPermissionChanges() {
     $this->drupalPost('admin/people/permissions', $edit, t('Save permissions'));
     $this->assertText(t('The changes have been saved.'), 'Successful save message displayed.');
     drupal_static_reset('user_access');
-    drupal_static_reset('user_role_permissions');
+    drupal_static_reset('user_roles');
     $this->assertTrue(user_access('administer nodes', $account), 'User now has "administer nodes" permission.');
 
     // Remove a permission.
@@ -57,7 +57,7 @@ function testUserPermissionChanges() {
     $this->drupalPost('admin/people/permissions', $edit, t('Save permissions'));
     $this->assertText(t('The changes have been saved.'), 'Successful save message displayed.');
     drupal_static_reset('user_access');
-    drupal_static_reset('user_role_permissions');
+    drupal_static_reset('user_roles');
     $this->assertFalse(user_access('access user profiles', $account), 'User no longer has "access user profiles" permission.');
   }
 
@@ -80,6 +80,8 @@ function testAdministratorRole() {
     // Aggregator depends on file module, enable that as well.
     $edit['modules[Core][file][enable]'] = TRUE;
     $this->drupalPost('admin/modules', $edit, t('Save configuration'));
+    drupal_static_reset('user_access');
+    drupal_static_reset('user_roles');
     $this->assertTrue(user_access('administer news feeds', $this->admin_user), 'The permission was automatically assigned to the administrator role');
   }
 
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/UserStorageController.php b/core/modules/user/lib/Drupal/user/UserStorageController.php
index 2b532c9..119b005 100644
--- a/core/modules/user/lib/Drupal/user/UserStorageController.php
+++ b/core/modules/user/lib/Drupal/user/UserStorageController.php
@@ -34,9 +34,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;
     }
 
     // Call the default attachLoad() method. This will add fields and call
diff --git a/core/modules/user/user.admin.inc b/core/modules/user/user.admin.inc
index 3668aae..2675bd5 100644
--- a/core/modules/user/user.admin.inc
+++ b/core/modules/user/user.admin.inc
@@ -5,6 +5,8 @@
  * Admin page callback file for the user module.
  */
 
+use Drupal\user\Plugin\Core\Entity\Role;
+
 function user_admin($callback_arg = '') {
   $op = isset($_POST['op']) ? $_POST['op'] : $callback_arg;
 
@@ -193,8 +195,7 @@ function user_admin_account() {
 
   $destination = drupal_get_destination();
   $status = array(t('blocked'), t('active'));
-  $roles = array_map('check_plain', user_roles(TRUE));
-  $accounts = array();
+  $roles = array_map('check_plain', user_role_names(TRUE));
   foreach ($result as $account) {
     $account = user_load($account->uid);
     $users_roles = array();
@@ -301,7 +302,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');
@@ -645,14 +646,13 @@ function user_admin_settings_submit($form, &$form_state) {
  * @see theme_user_admin_permissions()
  */
 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]);
   }
   // Fetch permissions for all roles or the one selected role.
-  $role_permissions = user_role_permissions($role_names);
+  $roles = user_roles();
 
   // Store $role_names for use when saving the data.
   $form['role_names'] = array(
@@ -693,7 +693,7 @@ function user_admin_permissions($form, $form_state, $rid = NULL) {
         );
         foreach ($role_names as $rid => $name) {
           // Builds arrays for checked boxes for each role
-          if (isset($role_permissions[$rid][$perm])) {
+          if (isset($roles[$rid]->permissions[$perm])) {
             $status[$rid][] = $perm;
           }
         }
@@ -748,7 +748,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
@@ -817,12 +817,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 = entity_load_multiple('user_role');
 
   $form['roles'] = array(
     '#tree' => TRUE,
@@ -889,8 +884,10 @@ function user_admin_roles($form, $form_state) {
 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);
+    if ($role->weight != $role_values['weight']) {
+      $role->weight = $role_values['weight'];
+      $role->save();
+    }
   }
   drupal_set_message(t('The role settings have been updated.'));
 }
@@ -942,8 +939,9 @@ function theme_user_admin_roles($variables) {
 /**
  * Form to configure a single role.
  *
- * @ingroup forms
  * @see user_admin_role_submit()
+ *
+ * @ingroup forms
  */
 function user_admin_role($form, $form_state, $role) {
   $form['role'] = array(
@@ -992,12 +990,11 @@ function user_admin_role($form, $form_state, $role) {
 }
 
 /**
- * Form submit handler for the user_admin_role() form.
+ * Form submission 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);
-  if ($status === SAVED_UPDATED) {
+  $role = entity_create('user_role', $form_state['values']['role']);
+  if ($role->save() === SAVED_UPDATED) {
     drupal_set_message(t('The role has been renamed.'));
   }
   else {
@@ -1014,9 +1011,17 @@ function user_admin_role_delete_submit($form, &$form_state) {
 }
 
 /**
- * Form to confirm role delete operation.
+ * Page callback: Form constructor for the role deletion form.
+ *
+ * @param Drupal\user\Plugin\Core\Entity\Role $role
+ *
+ * @see user_menu()
+ * @see user_admin_role_delete_confirm_submit()
+ *
+ * @ingroup forms
  */
-function user_admin_role_delete_confirm($form, &$form_state, $role) {
+function user_admin_role_delete_confirm($form, &$form_state, Role $role) {
+  $form_state['user_role'] = $role;
   $form['rid'] = array(
     '#type' => 'value',
     '#value' => $role->rid,
@@ -1025,10 +1030,11 @@ function user_admin_role_delete_confirm($form, &$form_state, $role) {
 }
 
 /**
- * Form submit handler for user_admin_role_delete_confirm().
+ * Form submission handler for user_admin_role_delete_confirm().
  */
 function user_admin_role_delete_confirm_submit($form, &$form_state) {
-  user_role_delete($form_state['values']['rid']);
+  $role = $form_state['user_role'];
+  $role->delete();
   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 bb86002..84e1e9f 100644
--- a/core/modules/user/user.install
+++ b/core/modules/user/user.install
@@ -191,75 +191,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(
-      'rid' => array(
-        'type' => 'varchar',
-        'length' => 64,
-        'not null' => TRUE,
-        'description' => 'Foreign Key: {role}.rid.',
-      ),
-      'permission' => array(
-        'type' => 'varchar',
-        'length' => 128,
-        'not null' => TRUE,
-        'default' => '',
-        'description' => 'A single permission granted to the role identified by rid.',
-      ),
-      'module' => array(
-        'type' => 'varchar',
-        'length' => 255,
-        'not null' => TRUE,
-        'default' => '',
-        'description' => "The module declaring the permission.",
-      ),
-    ),
-    'primary key' => array('rid', 'permission'),
-    'indexes' => array(
-      'permission' => array('permission'),
-    ),
-    'foreign keys' => array(
-      'role' => array(
-        'table' => 'role',
-        'columns' => array('rid' => 'rid'),
-      ),
-    ),
-  );
-
   $schema['users_data'] = array(
     'description' => 'Stores module data as key/value pairs per user.',
     'fields' => array(
@@ -369,13 +300,6 @@ function user_install() {
       'status' => 1,
     ))
     ->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();
 }
 
 /**
@@ -964,6 +888,34 @@ function user_update_8016() {
 }
 
 /**
+ * Turn the {role} table into configuration entities.
+ */
+function user_update_8017() {
+  $roles = db_select('role', 'r')
+    ->fields('r')
+    ->execute()
+    ->fetchAll();
+
+  foreach ($roles as $role) {
+    $permissions = db_select('role_permission', 'rp')
+      ->fields('rp', array('permission'))
+      ->condition('rid', $role->rid)
+      ->execute()
+      ->fetchAllKeyed(0, 0);
+
+    config('user.role.' . $role->rid)
+      ->set('rid', $role->rid)
+      ->set('name', $role->name)
+      ->set('weight', $role->weight)
+      ->set('permissions', $permissions ?: array())
+      ->save();
+  }
+
+  db_drop_table('role');
+  db_drop_table('role_permission');
+}
+
+/**
  * @} End of "addtogroup updates-7.x-to-8.x".
  */
 
diff --git a/core/modules/user/user.module b/core/modules/user/user.module
index ec43ade..d5e0661 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\Plugin\Core\Entity\File;
 use Drupal\Core\Template\Attribute;
@@ -390,52 +391,6 @@ function user_password($length = 10) {
 }
 
 /**
- * Determine the permissions for one or more roles.
- *
- * @param $roles
- *   An array whose keys are the role IDs of interest, such as $user->roles.
- *
- * @return
- *   An array indexed by role ID. Each value is an array whose keys are the
- *   permission strings for the given role ID.
- */
-function user_role_permissions($roles = array()) {
-  $cache = &drupal_static(__FUNCTION__, array());
-
-  $role_permissions = $fetch = array();
-
-  if ($roles) {
-    foreach ($roles as $rid => $name) {
-      if (isset($cache[$rid])) {
-        $role_permissions[$rid] = $cache[$rid];
-      }
-      else {
-        // Add this rid to the list of those needing to be fetched.
-        $fetch[] = $rid;
-        // Prepare in case no permissions are returned.
-        $cache[$rid] = array();
-      }
-    }
-
-    if ($fetch) {
-      // Get from the database permissions that were not in the static variable.
-      // Only role IDs with at least one permission assigned will return rows.
-      $result = db_query("SELECT rid, permission FROM {role_permission} WHERE rid IN (:fetch)", array(':fetch' => $fetch));
-
-      foreach ($result as $row) {
-        $cache[$row->rid][$row->permission] = TRUE;
-      }
-      foreach ($fetch as $rid) {
-        // For every rid, we know we at least assigned an empty array.
-        $role_permissions[$rid] = $cache[$rid];
-      }
-    }
-  }
-
-  return $role_permissions;
-}
-
-/**
  * Determine whether the user has a given privilege.
  *
  * @param $string
@@ -451,10 +406,8 @@ function user_role_permissions($roles = array()) {
  * can perform all actions.
  */
 function user_access($string, $account = NULL) {
-  global $user;
-
   if (!isset($account)) {
-    $account = $user;
+    $account = $GLOBALS['user'];
   }
 
   // User #1 has all privileges:
@@ -462,22 +415,19 @@ function user_access($string, $account = NULL) {
     return TRUE;
   }
 
-  // To reduce the number of SQL queries, we cache the user's permissions
-  // in a static variable.
-  // Use the advanced drupal_static() pattern, since this is called very often.
+  // To reduce the number of queries, we cache the user's permissions in a
+  // static variable. Use the advanced drupal_static() pattern, since this is
+  // called very often.
   static $drupal_static_fast;
   if (!isset($drupal_static_fast)) {
     $drupal_static_fast['perm'] = &drupal_static(__FUNCTION__);
   }
   $perm = &$drupal_static_fast['perm'];
   if (!isset($perm[$account->uid])) {
-    $role_permissions = user_role_permissions($account->roles);
-
-    $perms = array();
-    foreach ($role_permissions as $one_role) {
-      $perms += $one_role;
+    $perm[$account->uid] = array();
+    foreach (array_intersect_key(user_roles(), $account->roles) as $role) {
+      $perm[$account->uid] = array_merge($perm[$account->uid], $role->permissions);
     }
-    $perm[$account->uid] = $perms;
   }
 
   return isset($perm[$account->uid][$string]);
@@ -2038,147 +1988,65 @@ function user_mail_tokens(&$replacements, $data, $options) {
   }
 }
 
-/*** Administrative features ***********************************************/
+/**
+ * Retrieves an array of names of roles matching specified conditions.
+ *
+ * @param bool $membersonly
+ *   Set this to TRUE to exclude the 'anonymous' role.
+ * @param string $permission
+ *   A string containing a permission. If set, only names of roles containing
+ *   that permission are returned.
+ *
+ * @return array
+ *   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.
+ * Retrieves an array of roles matching specified conditions.
  *
- * @param $membersonly
+ * @param bool $membersonly
  *   Set this to TRUE to exclude the 'anonymous' role.
- * @param $permission
- *   A string containing a permission. If set, only roles containing that
+ * @param string $permission
+ *   A string representing 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 name as
+ * @return array
+ *   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__);
-
-  // Do not cache roles for specific permissions. This data is not requested
-  // frequently enough to justify the additional memory use.
-  if (empty($permission)) {
-    $cid = $membersonly ? DRUPAL_AUTHENTICATED_RID : DRUPAL_ANONYMOUS_RID;
-    if (isset($user_roles[$cid])) {
-      return $user_roles[$cid];
-    }
+  $cache = &drupal_static(__FUNCTION__);
+  if (!isset($cache)) {
+    $cache = entity_load_multiple('user_role');
   }
 
-  $query = db_select('role', 'r');
-  $query->addTag('translatable');
-  $query->fields('r', array('rid', 'name'));
-  $query->orderBy('weight');
-  $query->orderBy('name');
-  if (!empty($permission)) {
-    $query->innerJoin('role_permission', 'p', 'r.rid = p.rid');
-    $query->condition('p.permission', $permission);
-  }
+  $roles = $cache;
   if ($membersonly) {
-    $query->condition('r.rid', DRUPAL_ANONYMOUS_RID, '!=');
-  }
-  $roles = $query->execute()->fetchAllKeyed();
-
-  if (empty($permission)) {
-    $user_roles[$cid] = $roles;
-    return $user_roles[$cid];
+    unset($roles[DRUPAL_ANONYMOUS_RID]);
   }
 
-  return $roles;
+  return !$permission ? $roles : array_filter($roles, function ($role) use ($permission) {
+    return isset($role->permissions[$permission]);
+  });
 }
 
 /**
  * Fetches a user role by role ID.
  *
- * @param $rid
+ * @param string $rid
  *   A string representing the role ID.
  *
- * @return
- *   A fully-loaded role object if a role with the given ID exists, or FALSE
- *   otherwise.
+ * @return Drupal\user\Plugin\Core\Entity\Role
+ *   A fully-loaded role object or FALSE if there is no role with the given id.
  */
 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);
 }
 
 /**
@@ -2194,23 +2062,6 @@ function user_role_delete_access($role) {
 }
 
 /**
- * Determine the modules that permissions belong to.
- *
- * @return
- *   An associative array in the format $permission => $module.
- */
-function user_permission_get_modules() {
-  $permissions = array();
-  foreach (module_implements('permission') as $module) {
-    $perms = module_invoke($module, 'permission');
-    foreach ($perms as $key => $value) {
-      $permissions[$key] = $module;
-    }
-  }
-  return $permissions;
-}
-
-/**
  * Change permissions for a user role.
  *
  * This function may be used to grant and revoke multiple permissions at once.
@@ -2264,23 +2115,14 @@ function user_role_change_permissions($rid, array $permissions = array()) {
  * @see user_role_revoke_permissions()
  */
 function user_role_grant_permissions($rid, array $permissions = array()) {
-  $modules = user_permission_get_modules();
   // Grant new permissions for the role.
-  foreach ($permissions as $name) {
-    db_merge('role_permission')
-      ->key(array(
-        'rid' => $rid,
-        'permission' => $name,
-      ))
-      ->fields(array(
-        'module' => $modules[$name],
-      ))
-      ->execute();
-  }
+  $role = entity_load('user_role', $rid);
+  $role->permissions = array_merge($role->permissions, array_combine($permissions, $permissions));
+  $role->save();
 
   // Clear the user access cache.
   drupal_static_reset('user_access');
-  drupal_static_reset('user_role_permissions');
+  drupal_static_reset('user_roles');
 }
 
 /**
@@ -2296,14 +2138,13 @@ function user_role_grant_permissions($rid, array $permissions = array()) {
  */
 function user_role_revoke_permissions($rid, array $permissions = array()) {
   // Revoke permissions for the role.
-  db_delete('role_permission')
-    ->condition('rid', $rid)
-    ->condition('permission', $permissions, 'IN')
-    ->execute();
+  $role = entity_load('user_role', $rid);
+  $role->permissions = array_diff_key($role->permissions, array_flip($permissions));
+  $role->save();
 
   // Clear the user access cache.
   drupal_static_reset('user_access');
-  drupal_static_reset('user_role_permissions');
+  drupal_static_reset('user_roles');
 }
 
 /**
@@ -2325,7 +2166,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();
@@ -2410,7 +2251,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':
@@ -2546,7 +2387,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(
@@ -2605,13 +2446,14 @@ function user_build_filter_query(SelectInterface $query) {
     if ($key == 'permission') {
       $account = entity_create('user', array());
       $account->uid = 'user_filter';
-      $account->roles = array(DRUPAL_AUTHENTICATED_RID => 1);
+      $account->roles = array(DRUPAL_AUTHENTICATED_RID => DRUPAL_AUTHENTICATED_RID);
       if (user_access($value, $account)) {
         continue;
       }
+
+      $roles = array_keys(user_roles(FALSE, $value));
       $users_roles_alias = $query->join('users_roles', 'ur', '%alias.uid = u.uid');
-      $permission_alias = $query->join('role_permission', 'p', $users_roles_alias . '.rid = %alias.rid');
-      $query->condition($permission_alias . '.permission', $value);
+      $query->condition($users_roles_alias . '.rid', $roles ?: NULL);
     }
     elseif ($key == 'role') {
       $users_roles_alias = $query->join('users_roles', 'ur', '%alias.uid = u.uid');
@@ -2905,8 +2747,7 @@ function user_form_field_ui_field_edit_form_submit($form, &$form_state) {
  */
 function user_modules_installed($modules) {
   // Assign all available permissions to the administrator role.
-  $rid = config('user.settings')->get('admin_role');
-  if ($rid) {
+  if ($rid = config('user.settings')->get('admin_role')) {
     $permissions = array();
     foreach ($modules as $module) {
       if ($module_permissions = module_invoke($module, 'permission')) {
@@ -2923,9 +2764,11 @@ function user_modules_installed($modules) {
  * Implements hook_modules_uninstalled().
  */
 function user_modules_uninstalled($modules) {
-   db_delete('role_permission')
-     ->condition('module', $modules, 'IN')
-     ->execute();
+  $permissions = array_keys(module_invoke_all('permission'));
+  // Delete all permissions that are no longer available.
+  foreach (user_roles() as $role) {
+    user_role_revoke_permissions($role->rid, array_diff($role->permissions, $permissions));
+  }
   // Remove any potentially orphan module data stored for users.
   drupal_container()->get('user.data')->delete($modules);
 }
diff --git a/core/modules/user/user.views.inc b/core/modules/user/user.views.inc
index 48b6138..d9a0efa 100644
--- a/core/modules/user/user.views.inc
+++ b/core/modules/user/user.views.inc
@@ -351,22 +351,6 @@ function user_views_data() {
     ),
   );
 
-  // role table
-
-  $data['role']['table']['join'] = array(
-     // Directly links to users table.
-    'users' => array(
-      'left_table' => 'users_roles',
-      'left_field' => 'rid',
-      'field' => 'rid',
-    ),
-    // needed for many to one helper sometimes
-    'users_roles' => array(
-      'left_field' => 'rid',
-      'field' => 'rid',
-    ),
-  );
-
   // permission table
   $data['role_permission']['table']['group']  = t('User');
   $data['role_permission']['table']['join'] = 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 071bf31..9f722b3 100644
--- a/core/profiles/standard/standard.install
+++ b/core/profiles/standard/standard.install
@@ -394,11 +394,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();
