diff --git a/core/includes/update.inc b/core/includes/update.inc
index a5feb50..e170dd0 100644
--- a/core/includes/update.inc
+++ b/core/includes/update.inc
@@ -1597,3 +1597,35 @@ function update_add_cache_columns($table) {
     ));
   }
 }
+
+/**
+ * Replace permissions during update.
+ *
+ * This function can replace one permission to several or even delete an old
+ * one.
+ *
+ * @param array $replace
+ *   An associative array. The keys are the old permissions the values are a
+ *   list of new permissions. If the list is an empty array, the old permission
+ *   is removed.
+ */
+function update_replace_permissions($replace) {
+  $prefix = 'user.role.';
+  $cut = strlen($prefix);
+  $role_names = Drupal::service('config.storage')->listAll($prefix);
+  foreach ($role_names as $role_name) {
+    $rid = substr($role_name, $cut);
+    $config = Drupal::config("user.role.$rid");
+    $permissions = $config->get('permissions') ?: array();
+    foreach ($replace as $old_permission => $new_permissions) {
+      $key = array_search($old_permission, $permissions);
+      if ($key !== FALSE) {
+        unset($permissions[$key]);
+        $permissions = array_merge($permissions, $new_permissions);
+      }
+    }
+    $config
+      ->set('permissions', $permissions)
+      ->save();
+  }
+}
diff --git a/core/modules/block/lib/Drupal/block/Tests/BlockInterfaceTest.php b/core/modules/block/lib/Drupal/block/Tests/BlockInterfaceTest.php
index 58ff0c2..555d0cf 100644
--- a/core/modules/block/lib/Drupal/block/Tests/BlockInterfaceTest.php
+++ b/core/modules/block/lib/Drupal/block/Tests/BlockInterfaceTest.php
@@ -23,11 +23,6 @@ public static function getInfo() {
     );
   }
 
-  protected function setUp() {
-    parent::setUp();
-    $this->installSchema('user', 'role_permission');
-  }
-
   /**
    * Test configuration and subsequent form() and build() method calls.
    *
diff --git a/core/modules/comment/comment.module b/core/modules/comment/comment.module
index 7d848d6..54f744d 100644
--- a/core/modules/comment/comment.module
+++ b/core/modules/comment/comment.module
@@ -1221,18 +1221,22 @@ function comment_node_update_index(EntityInterface $node, $langcode) {
   $index_comments = &drupal_static(__FUNCTION__);
 
   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;
-    }
-
-    // Prevent indexing of comments if there are any roles that can search but
-    // not view comments.
+    // Do not index in the following three cases:
+    // 1. 'Authenticated user' can search content but can't access comments.
+    // 2. 'Anonymous user' can search content but can't access comments.
+    // 3. Any role can search content but can't access comments and access
+    // comments is not granted by the 'authenticated user' role. In this case
+    // all users might have both permissions from various roles but it is also
+    // possible to set up a user to have only search content and so a user
+    // edit could change the security situation so it is not safe to index the
+    // comments.
     $index_comments = TRUE;
-    foreach ($perms['search content'] as $rid) {
-      if (!isset($perms['access comments'][$rid]) && (($rid == DRUPAL_AUTHENTICATED_RID || $rid == DRUPAL_ANONYMOUS_RID) || !isset($perms['access comments'][DRUPAL_AUTHENTICATED_RID]))) {
+    $roles = user_roles();
+    $authenticated_can_access = in_array('access comments', $roles[DRUPAL_AUTHENTICATED_RID]->permissions);
+    foreach (user_roles() as $rid => $role_object) {
+      $permissions = $roles[$rid]->permissions;
+      if (in_array('search content', $permissions) && !in_array('access comments', $permissions) &&
+         ($rid == DRUPAL_AUTHENTICATED_RID || $rid == DRUPAL_ANONYMOUS_RID || !$authenticated_can_access)) {
         $index_comments = FALSE;
         break;
       }
diff --git a/core/modules/field_ui/field_ui.install b/core/modules/field_ui/field_ui.install
index 8ce3e2c..25fec01 100644
--- a/core/modules/field_ui/field_ui.install
+++ b/core/modules/field_ui/field_ui.install
@@ -10,36 +10,27 @@
  */
 function field_ui_update_8001() {
 
-  $permissions = array(
+  $replace = array(
     'administer comments' => array(
+      'administer comments',
       'administer comment fields',
       'administer comment display',
     ),
     'administer content types' => array(
+      'administer content types',
       'administer node fields',
       'administer node display',
     ),
     'administer users' => array(
+      'administer users',
       'administer user fields',
       'administer user display',
     ),
     'administer taxonomy' => array(
+      'administer taxonomy',
       'administer taxonomy_term fields',
       'administer taxonomy_term display',
     ),
   );
-
-  // We can not call user_permission_get_modules() as that will start
-  // invoking hooks which we can't during update hooks. Directly query
-  // for the permissions and insert them into the database.
-  foreach ($permissions as $old_permission => $new_permissions) {
-    $results = db_query("SELECT rid FROM {role_permission} WHERE permission = :permission", array(':permission' => $old_permission));
-    foreach ($results as $record) {
-      $query = db_insert('role_permission')->fields(array('rid', 'permission', 'module'));
-      foreach ($new_permissions as $new_permission) {
-        $query->values(array($record->rid, $new_permission, 'field_ui'));
-      }
-      $query->execute();
-    }
-  }
+  update_replace_permissions($replace);
 }
diff --git a/core/modules/filter/lib/Drupal/filter/Tests/FilterDefaultConfigTest.php b/core/modules/filter/lib/Drupal/filter/Tests/FilterDefaultConfigTest.php
index 85b5fef..f7f91d1 100644
--- a/core/modules/filter/lib/Drupal/filter/Tests/FilterDefaultConfigTest.php
+++ b/core/modules/filter/lib/Drupal/filter/Tests/FilterDefaultConfigTest.php
@@ -30,7 +30,7 @@ function setUp() {
     // filter_permission() calls into url() to output a link in the description.
     $this->installSchema('system', 'url_alias');
 
-    $this->installSchema('user', array('users_roles', 'role_permission'));
+    $this->installSchema('user', array('users_roles'));
 
     // Install filter_test module, which ships with custom default format.
     $this->installConfig(array('user', 'filter_test'));
diff --git a/core/modules/node/lib/Drupal/node/Tests/NodeAccessTest.php b/core/modules/node/lib/Drupal/node/Tests/NodeAccessTest.php
index 73b3a44..c073b4b 100644
--- a/core/modules/node/lib/Drupal/node/Tests/NodeAccessTest.php
+++ b/core/modules/node/lib/Drupal/node/Tests/NodeAccessTest.php
@@ -26,9 +26,7 @@ public static function getInfo() {
   function setUp() {
     parent::setUp();
     // Clear permissions for authenticated users.
-    db_delete('role_permission')
-      ->condition('rid', DRUPAL_AUTHENTICATED_RID)
-      ->execute();
+    $this->container->get('config.factory')->get('user.role.' . DRUPAL_AUTHENTICATED_RID)->clear('permissions');
   }
 
   /**
diff --git a/core/modules/node/node.install b/core/modules/node/node.install
index b0735d3..4366384 100644
--- a/core/modules/node/node.install
+++ b/core/modules/node/node.install
@@ -479,6 +479,15 @@ function _update_7000_node_get_types() {
  */
 
 /**
+ * Implements hook_update_dependency().
+ */
+function node_update_dependency() {
+  $dependencies['node'][8013] = array(
+    'user' => 8002,
+  );
+}
+
+/**
  * Rename node type language variable names.
  *
  * @see http://drupal.org/node/540294
@@ -704,15 +713,11 @@ function node_update_8012() {
  * Renames global revision permissions to use the word 'all'.
  */
 function node_update_8013() {
-  $actions = array('view', 'delete', 'revert');
-
-  foreach ($actions as $action) {
-    db_update('role_permission')
-      ->fields(array('permission' => $action . ' all revisions'))
-      ->condition('permission', $action . ' revisions')
-      ->condition('module', 'node')
-      ->execute();
-  }
+  update_replace_permissions(array(
+    'view revisions' => array('view all revisions'),
+    'revert revisions' => array('revert all revisions'),
+    'delete revisions' => array('delete all revisions'),
+  ));
 }
 
 /**
diff --git a/core/modules/node/node.views_execution.inc b/core/modules/node/node.views_execution.inc
index ead8702..f264bf2 100644
--- a/core/modules/node/node.views_execution.inc
+++ b/core/modules/node/node.views_execution.inc
@@ -30,17 +30,9 @@ function node_views_analyze(ViewExecutable $view) {
         // check for no access control
         $access = $display->getOption('access');
         if (empty($access['type']) || $access['type'] == 'none') {
-          $result = db_select('role_permission', 'p')
-            ->fields('p', array('rid', 'permission'))
-            ->condition('p.rid', array(DRUPAL_ANONYMOUS_RID, DRUPAL_AUTHENTICATED_RID), 'IN')
-            ->condition('p.permission', 'access content')
-            ->execute();
-
-          foreach ($result as $role) {
-            $role->safe = TRUE;
-            $roles[$role->rid] = $role;
-          }
-          if (!($roles[DRUPAL_ANONYMOUS_RID]->safe && $roles[DRUPAL_AUTHENTICATED_RID]->safe)) {
+          $anonymous_has_access = in_array('access content', entity_load('user_role', DRUPAL_ANONYMOUS_RID)->permissions);
+          $authenticated_has_access = in_array('access content', entity_load('user_role.', DRUPAL_AUTHENTICATED_RID)->permissions);
+          if (!$anonymous_has_access || !$authenticated_has_access) {
             $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');
diff --git a/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php b/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php
index 76988fa..753a616 100644
--- a/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php
+++ b/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php
@@ -551,8 +551,7 @@ protected function drupalCreateRole(array $permissions, $rid = NULL, $name = NUL
       // Grant the specified permissions to the role, if any.
       if (!empty($permissions)) {
         user_role_grant_permissions($role->id(), $permissions);
-
-        $assigned_permissions = db_query('SELECT permission FROM {role_permission} WHERE rid = :rid', array(':rid' => $role->id()))->fetchCol();
+        $assigned_permissions = entity_load('user_role', $role->id())->permissions;
         $missing_permissions = array_diff($permissions, $assigned_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/Entity/EntityAccessTest.php b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityAccessTest.php
index c29e4f3..300c4f6 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityAccessTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityAccessTest.php
@@ -29,7 +29,7 @@ public static function getInfo() {
 
   function setUp() {
     parent::setUp();
-    $this->installSchema('user', array('role_permission', 'users_roles'));
+    $this->installSchema('user', array('users_roles'));
     $this->installSchema('system', array('variable', 'url_alias'));
     $this->installSchema('language', 'language');
 
diff --git a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityBCDecoratorTest.php b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityBCDecoratorTest.php
index 892fd18..27a45fb 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityBCDecoratorTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityBCDecoratorTest.php
@@ -31,7 +31,7 @@ public static function getInfo() {
 
   public function setUp() {
     parent::setUp();
-    $this->installSchema('user', array('users_roles', 'users_data', 'role_permission'));
+    $this->installSchema('user', array('users_data'));
     $this->installSchema('node', array('node', 'node_revision', 'node_type', 'node_access'));
     $this->installSchema('comment', array('comment', 'node_comment_statistics'));
   }
diff --git a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityUnitTestBase.php b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityUnitTestBase.php
index 41918d3..1f65ff9 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityUnitTestBase.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityUnitTestBase.php
@@ -36,8 +36,7 @@ public function setUp() {
    *   (optional) The values used to create the entity.
    * @param array $permissions
    *   (optional) Array of permission names to assign to user. The
-   *   role_permission and users_roles tables must be installed before this can
-   *   be used.
+   *   users_roles tables must be installed before this can be used.
    *
    * @return \Drupal\user\Plugin\Core\Entity\User
    *   The created user entity.
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..78cecbf 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 6b669a5..c800e6f 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Upgrade/LanguageUpgradePathTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Upgrade/LanguageUpgradePathTest.php
@@ -184,6 +184,8 @@ public function testLanguageNoPluralsUpgrade() {
    * Tests upgrading translations permissions.
    */
   public function testLanguagePermissionsUpgrade() {
+    // Insert a permission into the Drupal 7 database before running the
+    // upgrade.
     db_insert('role_permission')->fields(array(
       'rid' => 2,
       'permission' => 'translate content',
@@ -191,12 +193,8 @@ public function testLanguagePermissionsUpgrade() {
     ))->execute();
 
     $this->assertTrue($this->performUpgrade(), 'The upgrade was completed successfully.');
-
-    // 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(user_roles(FALSE, 'translate content'), 'No translate content role left in config.');
     // 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(user_roles(FALSE, 'translate all content'), 'Rename role translate content to translate all content was completed successfully.');
   }
 }
diff --git a/core/modules/system/system.install b/core/modules/system/system.install
index 2a6f76c..b95f63c 100644
--- a/core/modules/system/system.install
+++ b/core/modules/system/system.install
@@ -1521,13 +1521,12 @@ function system_update_8020() {
   $blocked_ips_exists = db_query_range('SELECT 1 FROM {blocked_ips}', 0, 1)->fetchField();
   if ($blocked_ips_exists) {
     // Rename the permission name.
-    db_update('role_permission')
-      ->fields(array(
-        'permission' => 'ban IP addresses',
-        'module' => 'ban',
-      ))
-      ->condition('permission', 'block IP addresses')
-      ->execute();
+    update_replace_permissions(array(
+      'block IP addresses' => array('ban IP addresses'),
+    ));
+    config('user.module.permission')
+      ->set('ban.ban IP addresses', TRUE)
+      ->save();
     // Rename {blocked_ips} table into {ban_ip}.
     db_rename_table('blocked_ips', 'ban_ip');
     // Remove all references to the removed action callback.
diff --git a/core/modules/translation/translation.install b/core/modules/translation/translation.install
index 61d014d..ad15ba0 100644
--- a/core/modules/translation/translation.install
+++ b/core/modules/translation/translation.install
@@ -10,10 +10,9 @@
  * Rename the translate content permission.
  */
 function translation_update_8000() {
-  db_update('role_permission')
-    ->fields(array('permission' => 'translate all content'))
-    ->condition('permission', 'translate content')
-    ->execute();
+  update_replace_permissions(array(
+    'translate content' => array('translate all content'),
+  ));
 }
 
 /**
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
index 62cc7d3..f4dd1b8 100644
--- a/core/modules/user/lib/Drupal/user/Plugin/Core/Entity/Role.php
+++ b/core/modules/user/lib/Drupal/user/Plugin/Core/Entity/Role.php
@@ -65,6 +65,13 @@ class Role extends ConfigEntityBase implements RoleInterface {
   public $weight;
 
   /**
+   * The permissions belonging to this role.
+   *
+   * @var array
+   */
+  public $permissions = array();
+
+  /**
    * {@inheritdoc}
    */
   public function uri() {
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 7aa22fe..ef1d089 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
@@ -40,32 +40,33 @@ function pre_render(&$values) {
     $this->items = array();
 
     foreach ($values as $result) {
-      $uids[] = $this->get_value($result);
+      $uids[] = $this->get_value($result, 'uid');
     }
 
     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');
+      $permission_names = \Drupal::moduleHandler()->invokeAll('permission');
+      $query = db_select('users_roles', 'u');
       $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'];
+      $rids = array();
+      foreach ($result as $row) {
+        $rids[$row->rid][] = $row->uid;
+      }
+      if ($rids) {
+        $roles = entity_load_multiple('user_role', array_keys($rids));
+        foreach ($rids as $rid => $role_uids) {
+          foreach ($roles[$rid]->permissions as $permission) {
+            foreach ($role_uids as $uid) {
+              $this->items[$uid][$permission]['permission'] = $permission_names[$permission]['title'];
+            }
+          }
+        }
+      }
+      foreach ($uids as $uid) {
+        if (isset($this->items[$uid])) {
+          ksort($this->items[$uid]);
+        }
       }
     }
   }
diff --git a/core/modules/user/lib/Drupal/user/Plugin/views/filter/Permissions.php b/core/modules/user/lib/Drupal/user/Plugin/views/filter/Permissions.php
index 54f24f8..62db56b 100644
--- a/core/modules/user/lib/Drupal/user/Plugin/views/filter/Permissions.php
+++ b/core/modules/user/lib/Drupal/user/Plugin/views/filter/Permissions.php
@@ -41,4 +41,25 @@ function get_value_options() {
     }
   }
 
+  /**
+   * {@inheritdoc}
+   *
+   * Replace the configured permission with a filter by all roles that have this
+   * permission.
+   */
+  public function query() {
+    // @todo user_role_names() should maybe support multiple permissions.
+    $rids = array();
+    // Get all roles, that have the configured permissions.
+    foreach ($this->value as $permission) {
+      $roles = user_role_names(FALSE, $permission);
+      $rids += array_keys($roles);
+    }
+    $rids = array_unique($rids);
+    $this->value = $rids;
+
+    // $this->value contains the role IDs that have the configured permission.
+    parent::query();
+  }
+
 }
diff --git a/core/modules/user/lib/Drupal/user/RoleStorageController.php b/core/modules/user/lib/Drupal/user/RoleStorageController.php
index 680b412..5a42ca8 100644
--- a/core/modules/user/lib/Drupal/user/RoleStorageController.php
+++ b/core/modules/user/lib/Drupal/user/RoleStorageController.php
@@ -34,25 +34,30 @@ public function preSave(EntityInterface $entity) {
    */
   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');
+    $prefix = 'user.permission.';
+    if ($ids) {
+      $names = array();
+      foreach ($ids as $id) {
+        $names[] = $prefix . $id;
+      }
+    }
+    else {
+      $names = \Drupal::service('config.storage')->listAll($prefix);
+    }
+    foreach ($names as $name) {
+      config($name)->init();
+    }
   }
 
   /**
    * {@inheritdoc}
    */
   protected function postDelete($entities) {
-    $rids = array_keys($entities);
-
-    // Delete permission assignments.
-    db_delete('role_permission')
-      ->condition('rid', $rids)
-      ->execute();
     // Remove the role from all users.
     db_delete('users_roles')
-      ->condition('rid', $rids)
+      ->condition('rid', array_keys($entities))
       ->execute();
   }
 
diff --git a/core/modules/user/lib/Drupal/user/Tests/UserPermissionsTest.php b/core/modules/user/lib/Drupal/user/Tests/UserPermissionsTest.php
index 2455b10..348bb87 100644
--- a/core/modules/user/lib/Drupal/user/Tests/UserPermissionsTest.php
+++ b/core/modules/user/lib/Drupal/user/Tests/UserPermissionsTest.php
@@ -8,6 +8,7 @@
 namespace Drupal\user\Tests;
 
 use Drupal\simpletest\WebTestBase;
+use Drupal\user\RoleStorageController;
 
 class UserPermissionsTest extends WebTestBase {
   protected $admin_user;
@@ -46,8 +47,8 @@ function testUserPermissionChanges() {
     $edit[$rid . '[administer nodes]'] = TRUE;
     $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');
+    $storage_controller = $this->container->get('plugin.manager.entity')->getStorageController('user_role');
+    $storage_controller->resetCache();
     $this->assertTrue(user_access('administer nodes', $account), 'User now has "administer nodes" permission.');
 
     // Remove a permission.
@@ -56,8 +57,7 @@ function testUserPermissionChanges() {
     $edit[$rid . '[access user profiles]'] = FALSE;
     $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');
+    $storage_controller->resetCache();
     $this->assertFalse(user_access('access user profiles', $account), 'User no longer has "access user profiles" permission.');
   }
 
diff --git a/core/modules/user/lib/Drupal/user/Tests/Views/HandlerFieldPermissionTest.php b/core/modules/user/lib/Drupal/user/Tests/Views/HandlerFieldPermissionTest.php
new file mode 100644
index 0000000..ae84e4b
--- /dev/null
+++ b/core/modules/user/lib/Drupal/user/Tests/Views/HandlerFieldPermissionTest.php
@@ -0,0 +1,66 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\user\Tests\Views\HandlerFieldPermissionTest.
+ */
+
+namespace Drupal\user\Tests\Views;
+
+use Drupal\views\Tests\ViewTestData;
+use Drupal\views\Tests\ViewUnitTestBase;
+
+/**
+ * Tests the permission field handler.
+ *
+ * @see \Drupal\user\Plugin\views\field\Permissions
+ */
+class HandlerFieldPermissionTest extends UserUnitTestBase {
+
+  /**
+   * Views used by this test.
+   *
+   * @var array
+   */
+  public static $testViews = array('test_field_permission');
+
+  public static function getInfo() {
+    return array(
+      'name' => 'User: Permissions Field',
+      'description' => 'Tests the permission field handler.',
+      'group' => 'Views module integration',
+    );
+  }
+
+  /**
+   * Tests the permission field handler output.
+   */
+  public function testFieldPermission() {
+    $this->setupPermissionTestData();
+
+    $view = views_get_view('test_field_permission');
+    $this->executeView($view);
+    $view->initStyle();
+    $view->render();
+    $style_plugin = $view->style_plugin;
+
+    $expected_permissions = array();
+    $expected_permissions[$this->users[0]->id()] = array();
+    $expected_permissions[$this->users[1]->id()] = array();
+    $expected_permissions[$this->users[2]->id()][] = t('Administer permissions');
+    // View user profiles comes first, because we sort by the permission
+    // machine name.
+    $expected_permissions[$this->users[3]->id()][] = t('View user profiles');
+    $expected_permissions[$this->users[3]->id()][] = t('Administer permissions');
+    $expected_permissions[$this->users[3]->id()][] = t('Administer users');
+
+    foreach ($view->result as $index => $row) {
+      $uid = $view->field['uid']->get_value($row);
+      $rendered_permission = $style_plugin->get_field($index, 'permission');
+
+      $expected_output = implode(', ', $expected_permissions[$uid]);
+      $this->assertEqual($rendered_permission, $expected_output, 'The right permissions are rendered.');
+    }
+  }
+
+}
diff --git a/core/modules/user/lib/Drupal/user/Tests/Views/HandlerFilterPermissionTest.php b/core/modules/user/lib/Drupal/user/Tests/Views/HandlerFilterPermissionTest.php
new file mode 100644
index 0000000..c8ca5d7
--- /dev/null
+++ b/core/modules/user/lib/Drupal/user/Tests/Views/HandlerFilterPermissionTest.php
@@ -0,0 +1,131 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\user\Tests\Views\HandlerFilterPermissionTest.
+ */
+
+namespace Drupal\user\Tests\Views;
+
+use Drupal\user\Tests\Views\UserUnitTestBase;
+
+/**
+ * Tests the permissions filter handler.
+ *
+ * @see \Drupal\user\Plugin\views\filter\Permissions
+ */
+class HandlerFilterPermissionTest extends UserUnitTestBase {
+
+  /**
+   * Views used by this test.
+   *
+   * @var array
+   */
+  public static $testViews = array('test_filter_permission');
+
+  protected $columnMap;
+
+  public static function getInfo() {
+    return array(
+      'name' => 'User: Permissions Filter',
+      'description' => 'Tests the permission filter handler.',
+      'group' => 'Views module integration',
+    );
+  }
+
+  /**
+   * Tests the permission filter handler.
+   *
+   * @todo Fix the different commented out tests by fixing the many to one
+   *   handler handling with the NOT operator.
+   */
+  public function testFilterPermission() {
+    $this->setupPermissionTestData();
+
+    $column_map = array('uid' => 'uid');
+    $view = views_get_view('test_filter_permission');
+
+    // Filter by a non existing permission.
+    $view->initHandlers();
+    $view->filter['permission']->value = array('non_existent_permission');
+    $this->executeView($view);
+    $this->assertEqual(count($view->result), 4, 'A non existent permission is not filtered so everything is the result.');
+    $expected[] = array('uid' => 1);
+    $expected[] = array('uid' => 2);
+    $expected[] = array('uid' => 3);
+    $expected[] = array('uid' => 4);
+    $this->assertIdenticalResultset($view, $expected, $column_map);
+    $view->destroy();
+
+    // Filter by a non existing permission with operator NOT.
+    // $view->initHandlers();
+    // $view->filter['permission']->value = array('Non existent permission');
+    // $view->filter['permission']->operator = 'not';
+    // $this->executeView($view);
+    // $this->assertEqual(count($view->result), count($this->users), 'A non existent permission with the NOt operator should result in every user');
+    // $expected = array();
+    // $expected[] = array('uid' => 1);
+    // $expected[] = array('uid' => 2);
+    // $expected[] = array('uid' => 3);
+    // $expected[] = array('uid' => 4);
+    // $this->assertIdenticalResultset($view, $expected, $column_map);
+    // $view->destroy();
+
+    // Filter by a permission.
+    $view->initHandlers();
+    $view->filter['permission']->value = array('administer permissions');
+    $this->executeView($view);
+    $this->assertEqual(count($view->result), 2);
+    $expected = array();
+    $expected[] = array('uid' => 3);
+    $expected[] = array('uid' => 4);
+    $this->assertIdenticalResultset($view, $expected, $column_map);
+    $view->destroy();
+
+    // Filter by a permission with operator NOT.
+    // $view->initHandlers();
+    // $view->filter['permission']->value = array('administer permissions');
+    // $view->filter['permission']->operator = 'not';
+    // $this->executeView($view);
+    // $this->assertEqual(count($view->result), 2);
+    // $expected = array();
+    // $expected[] = array('uid' => 1);
+    // $expected[] = array('uid' => 2);
+    // $this->assertIdenticalResultset($view, $expected, $column_map);
+    // $view->destroy();
+
+    // Filter by another permission of a role with multiple permissions.
+    $view->initHandlers();
+    $view->filter['permission']->value = array('administer users');
+    $this->executeView($view);
+    $this->assertEqual(count($view->result), 1);
+    $expected = array();
+    $expected[] = array('uid' => 4);
+    $this->assertIdenticalResultset($view, $expected, $column_map);
+    $view->destroy();
+
+    // Filter by another permission of a role with multiple permissions and
+    // operator NOT.
+    // $view->initHandlers();
+    // $view->filter['permission']->value = array('administer users');
+    // $view->filter['permission']->operator = 'not';
+    // $this->executeView($view);
+    // $this->assertEqual(count($view->result), 3);
+    // $expected = array();
+    // $expected[] = array('uid' => 1);
+    // $expected[] = array('uid' => 2);
+    // $expected[] = array('uid' => 3);
+    // $this->assertIdenticalResultset($view, $expected, $column_map);
+    // $view->destroy();
+
+    $view->initDisplay();
+    $view->initHandlers();
+    $view->filter['permission']->get_value_options();
+
+    $expected = array_map(function ($permission) {
+      return check_plain(strip_tags($permission['title']));
+    }, $this->container->get('module_handler')->invokeAll('permission'));
+    $this->assertEqual($view->filter['permission']->value_options, $expected, 'Ensure the all permissions are available');
+  }
+
+}
diff --git a/core/modules/user/lib/Drupal/user/Tests/Views/UserUnitTestBase.php b/core/modules/user/lib/Drupal/user/Tests/Views/UserUnitTestBase.php
new file mode 100644
index 0000000..0071f12
--- /dev/null
+++ b/core/modules/user/lib/Drupal/user/Tests/Views/UserUnitTestBase.php
@@ -0,0 +1,90 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\user\Tests\Views\UserUnitTestBase.
+ */
+
+namespace Drupal\user\Tests\Views;
+
+use Drupal\views\Tests\ViewTestData;
+use Drupal\views\Tests\ViewUnitTestBase;
+
+/**
+ * Provides a common test base for user views tests.
+ */
+abstract class UserUnitTestBase extends ViewUnitTestBase {
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = array('user_test_views', 'user', 'system', 'field');
+
+  /**
+   * Users to use during this test.
+   *
+   * @var array
+   */
+  protected $users = array();
+
+  /**
+   * The entity storage controller for roles.
+   *
+   * @var \Drupal\user\RoleStorageController
+   */
+  protected $roleStorageController;
+
+  /**
+   * The entity storage controller for users.
+   *
+   * @var \Drupal\user\UserStorageController
+   */
+  protected $userStorageController;
+
+  protected function setUp() {
+    parent::setUp();
+
+    ViewTestData::importTestViews(get_class($this), array('user_test_views'));
+
+    $this->installSchema('user', array('users', 'users_roles'));
+    $this->installSchema('system', 'sequences');
+
+    $entity_manager = $this->container->get('plugin.manager.entity');
+    $this->roleStorageController = $entity_manager->getStorageController('user_role');
+    $this->userStorageController = $entity_manager->getStorageController('user');
+  }
+
+  /**
+   * Set some test data for permission related tests.
+   */
+  protected function setupPermissionTestData() {
+    // Setup a role without any permission.
+    $this->roleStorageController->create(array('id' => 'no_permission'))
+      ->save();
+    // Setup a role with just one permission.
+    $this->roleStorageController->create(array('id' => 'one_permission'))
+      ->save();
+    user_role_grant_permissions('one_permission', array('administer permissions'));
+    // Setup a role with multiple permissions.
+    $this->roleStorageController->create(array('id' => 'multiple_permissions'))
+      ->save();
+    user_role_grant_permissions('multiple_permissions', array('administer permissions', 'administer users', 'access user profiles'));
+
+    // Setup a user without an extra role.
+    $this->users[] = $account = $this->userStorageController->create(array());
+    $account->save();
+    // Setup a user with just the first role (so no permission beside the
+    // ones from the authenticated role).
+    $this->users[] = $account = $this->userStorageController->create(array('name' => 'first_role', 'roles' => array('no_permission' => 'no_permission')));
+    $account->save();
+    // Setup a user with just the second role (so one additional permission).
+    $this->users[] = $account = $this->userStorageController->create(array('name' => 'second_role', 'roles' => array('one_permission' => 'one_permission')));
+    $account->save();
+    // Setup a user with both the second and the third role.
+    $this->users[] = $account = $this->userStorageController->create(array('name' => 'second_third_role', 'roles' => array('one_permission' => 'one_permission', 'multiple_permissions' => 'multiple_permissions')));
+    $account->save();
+  }
+
+}
diff --git a/core/modules/user/tests/modules/user_test_views/test_views/views.view.test_field_permission.yml b/core/modules/user/tests/modules/user_test_views/test_views/views.view.test_field_permission.yml
new file mode 100644
index 0000000..94f587d
--- /dev/null
+++ b/core/modules/user/tests/modules/user_test_views/test_views/views.view.test_field_permission.yml
@@ -0,0 +1,135 @@
+base_field: uid
+base_table: users
+core: 8.x
+description: ''
+status: '1'
+display:
+  default:
+    display_plugin: default
+    id: default
+    display_title: Master
+    position: ''
+    display_options:
+      access:
+        type: none
+      cache:
+        type: none
+      query:
+        type: views_query
+      exposed_form:
+        type: basic
+      pager:
+        type: full
+      style:
+        type: default
+      row:
+        type: fields
+      fields:
+        uid:
+          id: uid
+          table: users
+          field: uid
+          relationship: none
+          group_type: group
+          admin_label: ''
+          label: Uid
+          exclude: '0'
+          alter:
+            alter_text: '0'
+            text: ''
+            make_link: '0'
+            path: ''
+            absolute: '0'
+            external: '0'
+            replace_spaces: '0'
+            path_case: none
+            trim_whitespace: '0'
+            alt: ''
+            rel: ''
+            link_class: ''
+            prefix: ''
+            suffix: ''
+            target: ''
+            nl2br: '0'
+            max_length: ''
+            word_boundary: '1'
+            ellipsis: '1'
+            more_link: '0'
+            more_link_text: ''
+            more_link_path: ''
+            strip_tags: '0'
+            trim: '0'
+            preserve_tags: ''
+            html: '0'
+          element_type: ''
+          element_class: ''
+          element_label_type: ''
+          element_label_class: ''
+          element_label_colon: '1'
+          element_wrapper_type: ''
+          element_wrapper_class: ''
+          element_default_classes: '1'
+          empty: ''
+          hide_empty: '0'
+          empty_zero: '0'
+          hide_alter_empty: '1'
+          link_to_user: '0'
+          plugin_id: user
+        permission:
+          id: permission
+          table: users_roles
+          field: permission
+          relationship: none
+          group_type: group
+          admin_label: ''
+          label: Permission
+          exclude: '0'
+          alter:
+            alter_text: '0'
+            text: ''
+            make_link: '0'
+            path: ''
+            absolute: '0'
+            external: '0'
+            replace_spaces: '0'
+            path_case: none
+            trim_whitespace: '0'
+            alt: ''
+            rel: ''
+            link_class: ''
+            prefix: ''
+            suffix: ''
+            target: ''
+            nl2br: '0'
+            max_length: ''
+            word_boundary: '1'
+            ellipsis: '1'
+            more_link: '0'
+            more_link_text: ''
+            more_link_path: ''
+            strip_tags: '0'
+            trim: '0'
+            preserve_tags: ''
+            html: '0'
+          element_type: ''
+          element_class: ''
+          element_label_type: ''
+          element_label_class: ''
+          element_label_colon: '1'
+          element_wrapper_type: ''
+          element_wrapper_class: ''
+          element_default_classes: '1'
+          empty: ''
+          hide_empty: '0'
+          empty_zero: '0'
+          hide_alter_empty: '1'
+          type: separator
+          separator: ', '
+          plugin_id: user_permissions
+      filters: {  }
+      sorts: {  }
+human_name: test_field_permission
+module: views
+id: test_field_permission
+tag: ''
+langcode: en
diff --git a/core/modules/user/tests/modules/user_test_views/test_views/views.view.test_filter_permission.yml b/core/modules/user/tests/modules/user_test_views/test_views/views.view.test_filter_permission.yml
new file mode 100644
index 0000000..ef1fd1c
--- /dev/null
+++ b/core/modules/user/tests/modules/user_test_views/test_views/views.view.test_filter_permission.yml
@@ -0,0 +1,123 @@
+base_field: uid
+base_table: users
+core: 8.x
+description: ''
+status: '1'
+display:
+  default:
+    display_plugin: default
+    id: default
+    display_title: Master
+    position: ''
+    display_options:
+      access:
+        type: none
+      cache:
+        type: none
+      query:
+        type: views_query
+      exposed_form:
+        type: basic
+      pager:
+        type: full
+      style:
+        type: default
+      row:
+        type: fields
+      fields:
+        uid:
+          id: uid
+          table: users
+          field: uid
+          relationship: none
+          group_type: group
+          admin_label: ''
+          label: ''
+          exclude: '0'
+          alter:
+            alter_text: '0'
+            text: ''
+            make_link: '0'
+            path: ''
+            absolute: '0'
+            external: '0'
+            replace_spaces: '0'
+            path_case: none
+            trim_whitespace: '0'
+            alt: ''
+            rel: ''
+            link_class: ''
+            prefix: ''
+            suffix: ''
+            target: ''
+            nl2br: '0'
+            max_length: ''
+            word_boundary: '1'
+            ellipsis: '1'
+            more_link: '0'
+            more_link_text: ''
+            more_link_path: ''
+            strip_tags: '0'
+            trim: '0'
+            preserve_tags: ''
+            html: '0'
+          element_type: ''
+          element_class: ''
+          element_label_type: ''
+          element_label_class: ''
+          element_label_colon: '0'
+          element_wrapper_type: ''
+          element_wrapper_class: ''
+          element_default_classes: '1'
+          empty: ''
+          hide_empty: '0'
+          empty_zero: '0'
+          hide_alter_empty: '1'
+          link_to_user: '0'
+          plugin_id: user
+      filters:
+        permission:
+          id: permission
+          table: users_roles
+          field: permission
+          relationship: none
+          group_type: group
+          admin_label: ''
+          operator: or
+          value:
+            'access user profiles': 'access user profiles'
+          group: '1'
+          exposed: '0'
+          expose:
+            operator_id: '0'
+            label: ''
+            description: ''
+            use_operator: '0'
+            operator: ''
+            identifier: ''
+            required: '0'
+            remember: '0'
+            multiple: '0'
+            remember_roles:
+              authenticated: authenticated
+            reduce: '0'
+          is_grouped: '0'
+          group_info:
+            label: ''
+            description: ''
+            identifier: ''
+            optional: '1'
+            widget: select
+            multiple: '0'
+            remember: '0'
+            default_group: All
+            default_group_multiple: {  }
+            group_items: {  }
+          reduce_duplicates: '1'
+          plugin_id: user_permissions
+      sorts: {  }
+human_name: test_filter_permission
+module: views
+id: test_filter_permission
+tag: ''
+langcode: en
diff --git a/core/modules/user/user.install b/core/modules/user/user.install
index dca417c..b57d760 100644
--- a/core/modules/user/user.install
+++ b/core/modules/user/user.install
@@ -148,42 +148,6 @@ function user_schema() {
     ),
   );
 
-  $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(
@@ -437,9 +401,6 @@ function user_update_8002() {
   );
   db_change_field('role', 'rid', 'rid', $column);
 
-  $column['description'] = 'Foreign Key: {role}.rid.';
-  db_change_field('role_permission', 'rid', 'rid', $column);
-
   $column['description'] = 'Primary Key: {role}.rid for role.';
   db_change_field('users_roles', 'rid', 'rid', $column);
 
@@ -456,32 +417,16 @@ function user_update_8002() {
   db_drop_unique_key('role', 'name');
 
   // Rename the built-in serial role IDs into the hardcoded machine names.
-  db_update('role')
-    ->fields(array('rid' => DRUPAL_ANONYMOUS_RID))
-    ->condition('rid', 1)
-    ->execute();
-  db_update('role')
-    ->fields(array('rid' => DRUPAL_AUTHENTICATED_RID))
-    ->condition('rid', 2)
-    ->execute();
-
-  db_update('role_permission')
-    ->fields(array('rid' => DRUPAL_ANONYMOUS_RID))
-    ->condition('rid', 1)
-    ->execute();
-  db_update('role_permission')
-    ->fields(array('rid' => DRUPAL_AUTHENTICATED_RID))
-    ->condition('rid', 2)
-    ->execute();
-
-  db_update('users_roles')
-    ->fields(array('rid' => DRUPAL_ANONYMOUS_RID))
-    ->condition('rid', 1)
-    ->execute();
-  db_update('users_roles')
-    ->fields(array('rid' => DRUPAL_AUTHENTICATED_RID))
-    ->condition('rid', 2)
-    ->execute();
+  foreach (array(1, 2) as $rid) {
+    db_update('role')
+      ->fields(array('rid' => _user_update_map_rid($rid)))
+      ->condition('rid', $rid)
+      ->execute();
+    db_update('users_roles')
+      ->fields(array('rid' => _user_update_map_rid($rid)))
+      ->condition('rid', $rid)
+      ->execute();
+  }
 }
 
 /**
@@ -1051,5 +996,43 @@ function user_update_8017() {
 }
 
 /**
+ * Maps a role id to the new string.
+ *
+ * @param int $rid
+ *   A D7 numeric role ID.
+ *
+ * @return string
+ *   A D8 string role ID.
+ */
+function _user_update_map_rid($rid) {
+  $rid_map = array(
+    1 => DRUPAL_ANONYMOUS_RID,
+    2 => DRUPAL_AUTHENTICATED_RID,
+  );
+  return isset($rid_map[$rid]) ? $rid_map[$rid] : $rid;
+}
+
+/**
+ * Migrate roles permissions into configuration.
+ *
+ * @ingroup config_upgrade
+ */
+function user_update_8018() {
+  $db_permissions = db_select('role_permission', 'p')
+    ->fields('p')
+    ->execute()
+    ->fetchAll();
+  $new_permissions = array();
+  foreach ($db_permissions as $permission) {
+    $new_permissions[_user_update_map_rid($permission->rid)][] = $permission->permission;
+  }
+  foreach ($new_permissions as $rid => $permissions) {
+    config("user.role.$rid")
+      ->set('permissions', $permissions)
+      ->save();
+  }
+}
+
+/**
  * @} End of "addtogroup updates-7.x-to-8.x".
  */
diff --git a/core/modules/user/user.module b/core/modules/user/user.module
index 3ae6154..ae6fb0c 100644
--- a/core/modules/user/user.module
+++ b/core/modules/user/user.module
@@ -7,7 +7,6 @@
 use Drupal\entity\Plugin\Core\Entity\EntityDisplay;
 use Drupal\file\Plugin\Core\Entity\File;
 use Drupal\user\Plugin\Core\Entity\User;
-use Drupal\user\UserRole;
 use Drupal\Core\Template\Attribute;
 use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
 use Drupal\menu_link\Plugin\Core\Entity\MenuLink;
@@ -414,41 +413,21 @@ function user_password($length = 10) {
 /**
  * Determine the permissions for one or more roles.
  *
- * @param $roles
+ * @param array $roles
  *   An array whose keys are the role IDs of interest, such as $user->roles.
  *
- * @return
+ * @return array
  *   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) {
-  $cache = &drupal_static(__FUNCTION__, array());
-
-  $role_permissions = $fetch = array();
-
+function user_role_permissions(array $roles) {
+  $role_permissions = array();
   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];
+    $role_permissions[$rid] = array();
+    // Can not use the entity system as this function is used during update.
+    $permissions = Drupal::config("user.role.$rid")->get('permissions') ?: array();
+    foreach ($permissions as $permission) {
+      $role_permissions[$rid][$permission] = TRUE;
     }
   }
 
@@ -1870,12 +1849,11 @@ function user_roles($membersonly = FALSE, $permission = NULL) {
   }
 
   if (!empty($permission)) {
-    $result = db_select('role_permission', 'p')
-      ->fields('p', array('rid'))
-      ->condition('p.rid', array_keys($roles))
-      ->condition('p.permission', $permission)
-      ->execute()->fetchCol();
-    $roles = array_intersect_key($roles, array_flip($result));
+    foreach ($roles as $rid => $role_object) {
+      if (!in_array($permission, $role_object->permissions)) {
+        unset($roles[$rid]);
+      }
+    }
   }
 
   if (empty($permission)) {
@@ -1982,23 +1960,20 @@ 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 = entity_load('user_role', $rid);
+  $role_entity->permissions = array_unique(array_merge($role_entity->permissions, $permissions));
+  $role_entity->save();
+
+  $modules = user_permission_get_modules();
+  $config = Drupal::config('user.module.permission');
+  foreach ($modules as $permission => $module) {
+    $config->set("$module.$permission", TRUE);
   }
+  $config->save();
 
   // Clear the user access cache.
   drupal_static_reset('user_access');
-  drupal_static_reset('user_role_permissions');
 }
 
 /**
@@ -2014,14 +1989,11 @@ 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 = entity_load('user_role', $rid);
+  $role_entity->permissions = array_diff($role_entity->permissions, $permissions);
+  $role_entity->save();
   // Clear the user access cache.
   drupal_static_reset('user_access');
-  drupal_static_reset('user_role_permissions');
 }
 
 /**
@@ -2317,17 +2289,13 @@ function user_build_filter_query(SelectInterface $query) {
     // the authenticated role. If so, then all users would be listed, and we can
     // skip adding it to the filter query.
     if ($key == 'permission') {
-      $account = entity_create('user', array());
-      $account->uid = 'user_filter';
-      $account->roles = array(DRUPAL_AUTHENTICATED_RID => 1);
-      if (user_access($value, $account)) {
+      $roles = user_roles(FALSE, $value);
+      if (isset($roles[DRUPAL_AUTHENTICATED_RID])) {
         continue;
       }
-      $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);
+      $value = array_keys($roles);
     }
-    elseif ($key == 'role') {
+    if ($key == 'permission' || $key == 'role') {
       $users_roles_alias = $query->join('users_roles', 'ur', '%alias.uid = u.uid');
       $query->condition($users_roles_alias . '.rid' , $value);
     }
@@ -2635,11 +2603,25 @@ function user_modules_installed($modules) {
 
 /**
  * Implements hook_modules_uninstalled().
+ *
+ * Remove all permissions from the permission configurations for the uninstalled
+ * module.
  */
 function user_modules_uninstalled($modules) {
-   db_delete('role_permission')
-     ->condition('module', $modules, 'IN')
-     ->execute();
+  $config = Drupal::config('user.module.permission');
+  $permissions_to_remove = array();
+  foreach ($modules as $module) {
+    $permissions_to_remove += (array) $config->get($module);
+    $config->clear($module);
+  }
+  $config->save();
+  if ($permissions_to_remove) {
+    $permissions_to_remove = array_keys($permissions_to_remove);
+    foreach (user_roles() as $rid => $role_entity) {
+      $role_entity->permissions = array_diff($role_entity->permissions, $permissions_to_remove);
+      $role_entity->save();
+    }
+  }
   // 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 8a27f82..0a62d83 100644
--- a/core/modules/user/user.views.inc
+++ b/core/modules/user/user.views.inc
@@ -351,19 +351,7 @@ function user_views_data() {
     ),
   );
 
-  // Define the base group of this table. Fields that don't have a group defined
-  // will go into this field by default.
-  $data['role_permission']['table']['group']  = t('User');
-  // Explain how this table joins to others.
-  $data['role_permission']['table']['join'] = array(
-    'users' => array(
-      'left_table' => 'users_roles',
-      'left_field' => 'rid',
-      'field' => 'rid',
-    ),
-  );
-
-  $data['role_permission']['permission'] = array(
+  $data['users_roles']['permission'] = array(
     'title' => t('Permission'),
     'help' => t('The user permissions.'),
     'field' => array(
@@ -372,6 +360,7 @@ function user_views_data() {
     ),
     'filter' => array(
       'id' => 'user_permissions',
+      'real field' => 'rid',
     ),
   );
 
diff --git a/core/modules/views/lib/Drupal/views/ManyToOneHelper.php b/core/modules/views/lib/Drupal/views/ManyToOneHelper.php
index 1209901..1c38e3b 100644
--- a/core/modules/views/lib/Drupal/views/ManyToOneHelper.php
+++ b/core/modules/views/lib/Drupal/views/ManyToOneHelper.php
@@ -309,7 +309,7 @@ function add_filter() {
       else {
         $placeholder = $this->placeholder();
         if (count($this->handler->value) > 1) {
-          $this->query->add_where_expression(0, "$field $operator($placeholder)", array($placeholder => $value));
+          $this->handler->query->add_where_expression(0, "$field $operator($placeholder)", array($placeholder => $value));
         }
         else {
           $this->handler->query->add_where_expression(0, "$field $operator $placeholder", array($placeholder => $value));
diff --git a/core/modules/views/lib/Drupal/views/Tests/Handler/FieldCounterTest.php b/core/modules/views/lib/Drupal/views/Tests/Handler/FieldCounterTest.php
index 721b3c5..72af9bd 100644
--- a/core/modules/views/lib/Drupal/views/Tests/Handler/FieldCounterTest.php
+++ b/core/modules/views/lib/Drupal/views/Tests/Handler/FieldCounterTest.php
@@ -36,11 +36,6 @@ public static function getInfo() {
     );
   }
 
-  protected function setUp() {
-    parent::setUp();
-    $this->installSchema('user', 'role_permission');
-  }
-
   function testSimple() {
     $view = views_get_view('test_view');
     $view->setDisplay();
diff --git a/core/modules/views/lib/Drupal/views/Tests/Handler/FieldUnitTest.php b/core/modules/views/lib/Drupal/views/Tests/Handler/FieldUnitTest.php
index d5f2eac..643b683 100644
--- a/core/modules/views/lib/Drupal/views/Tests/Handler/FieldUnitTest.php
+++ b/core/modules/views/lib/Drupal/views/Tests/Handler/FieldUnitTest.php
@@ -38,11 +38,6 @@ public static function getInfo() {
     );
   }
 
-  public function setUp() {
-    parent::setUp();
-    $this->installSchema('user', 'role_permission');
-  }
-
   /**
    * Overrides Drupal\views\Tests\ViewTestBase::viewsData().
    */
diff --git a/core/modules/views/lib/Drupal/views/Tests/Plugin/RelationshipJoinTestBase.php b/core/modules/views/lib/Drupal/views/Tests/Plugin/RelationshipJoinTestBase.php
index 172678d..95a543f 100644
--- a/core/modules/views/lib/Drupal/views/Tests/Plugin/RelationshipJoinTestBase.php
+++ b/core/modules/views/lib/Drupal/views/Tests/Plugin/RelationshipJoinTestBase.php
@@ -26,7 +26,7 @@
    * Overrides \Drupal\views\Tests\ViewUnitTestBase::setUpFixtures().
    */
   protected function setUpFixtures() {
-    $this->installSchema('user', array('users', 'users_roles', 'role_permission'));
+    $this->installSchema('user', array('users', 'users_roles'));
     $this->installConfig(array('user'));
     parent::setUpFixtures();
 
diff --git a/core/modules/views/lib/Drupal/views/Tests/ViewExecutableTest.php b/core/modules/views/lib/Drupal/views/Tests/ViewExecutableTest.php
index 41e5c8b..8dd67ee 100644
--- a/core/modules/views/lib/Drupal/views/Tests/ViewExecutableTest.php
+++ b/core/modules/views/lib/Drupal/views/Tests/ViewExecutableTest.php
@@ -80,7 +80,7 @@ public static function getInfo() {
   }
 
   protected function setUpFixtures() {
-    $this->installSchema('user', array('users', 'role_permission'));
+    $this->installSchema('user', array('users'));
     $this->installSchema('node', array('node_type', 'node'));
     $this->installSchema('comment', array('comment', 'node_comment_statistics'));
     parent::setUpFixtures();
