diff --git a/core/modules/block/src/Tests/Migrate/d7/MigrateBlockTest.php b/core/modules/block/src/Tests/Migrate/d7/MigrateBlockTest.php
index cecf468..96636ba 100644
--- a/core/modules/block/src/Tests/Migrate/d7/MigrateBlockTest.php
+++ b/core/modules/block/src/Tests/Migrate/d7/MigrateBlockTest.php
@@ -38,6 +38,8 @@ class MigrateBlockTest extends MigrateDrupal7TestBase {
    */
   protected function setUp() {
     parent::setUp();
+    $this->installSchema('system', ['router']);
+    $this->container->get('router.builder')->rebuild();
     $this->installConfig(static::$modules);
     $this->installEntitySchema('block_content');
 
diff --git a/core/modules/comment/src/Tests/Migrate/d6/MigrateCommentTest.php b/core/modules/comment/src/Tests/Migrate/d6/MigrateCommentTest.php
index 4545e46..b52037b 100644
--- a/core/modules/comment/src/Tests/Migrate/d6/MigrateCommentTest.php
+++ b/core/modules/comment/src/Tests/Migrate/d6/MigrateCommentTest.php
@@ -39,7 +39,6 @@ protected function setUp() {
     $this->installEntitySchema('node');
     $this->installEntitySchema('comment');
     $this->installSchema('comment', ['comment_entity_statistics']);
-    $this->installSchema('system', ['router']);
     $this->installConfig(['comment']);
 
     // The entity.node.canonical route must exist when the RDF hook is called.
diff --git a/core/modules/comment/src/Tests/Migrate/d7/MigrateCommentTest.php b/core/modules/comment/src/Tests/Migrate/d7/MigrateCommentTest.php
index 6c7277e..b50e236 100644
--- a/core/modules/comment/src/Tests/Migrate/d7/MigrateCommentTest.php
+++ b/core/modules/comment/src/Tests/Migrate/d7/MigrateCommentTest.php
@@ -28,6 +28,8 @@ class MigrateCommentTest extends MigrateDrupal7TestBase {
   protected function setUp() {
     parent::setUp();
 
+    $this->installSchema('system', ['router']);
+    $this->container->get('router.builder')->rebuild();
     $this->installConfig(static::$modules);
     $this->installEntitySchema('node');
     $this->installEntitySchema('comment');
diff --git a/core/modules/filter/src/FilterPermissions.php b/core/modules/filter/src/FilterPermissions.php
index 8f4c597..9dc4188 100644
--- a/core/modules/filter/src/FilterPermissions.php
+++ b/core/modules/filter/src/FilterPermissions.php
@@ -64,6 +64,13 @@ public function permissions() {
             '#markup' => $this->t('Warning: This permission may have security implications depending on how the text format is configured.'),
             '#suffix' => '</em>'
           ],
+          // This permission is generated in behalf of $format text format, thus
+          // we add this text format as a config dependency.
+          'dependencies' => [
+            $format->getConfigDependencyKey() => [
+              $format->getConfigDependencyName(),
+            ],
+          ],
         ];
       }
     }
diff --git a/core/modules/filter/src/Tests/FilterAPITest.php b/core/modules/filter/src/Tests/FilterAPITest.php
index 263b31e..47762c1 100644
--- a/core/modules/filter/src/Tests/FilterAPITest.php
+++ b/core/modules/filter/src/Tests/FilterAPITest.php
@@ -283,6 +283,8 @@ function testProcessedTextElement() {
    * Tests the function of the typed data type.
    */
   function testTypedDataAPI() {
+    $this->installSchema('system', ['router']);
+    $this->container->get('router.builder')->rebuild();
     $definition = DataDefinition::create('filter_format');
     $data = \Drupal::typedDataManager()->create($definition);
 
diff --git a/core/modules/menu_link_content/src/Tests/Migrate/d6/MigrateMenuLinkTest.php b/core/modules/menu_link_content/src/Tests/Migrate/d6/MigrateMenuLinkTest.php
index f6346fc..795f5f0 100644
--- a/core/modules/menu_link_content/src/Tests/Migrate/d6/MigrateMenuLinkTest.php
+++ b/core/modules/menu_link_content/src/Tests/Migrate/d6/MigrateMenuLinkTest.php
@@ -27,7 +27,6 @@ class MigrateMenuLinkTest extends MigrateDrupal6TestBase {
    */
   protected function setUp() {
     parent::setUp();
-    $this->installSchema('system', ['router']);
     $this->installEntitySchema('menu_link_content');
     $this->executeMigrations(['menu', 'd6_menu_links']);
   }
diff --git a/core/modules/migrate_drupal/src/Tests/d6/MigrateDrupal6TestBase.php b/core/modules/migrate_drupal/src/Tests/d6/MigrateDrupal6TestBase.php
index 4a1f4d3..9fd41fc 100644
--- a/core/modules/migrate_drupal/src/Tests/d6/MigrateDrupal6TestBase.php
+++ b/core/modules/migrate_drupal/src/Tests/d6/MigrateDrupal6TestBase.php
@@ -35,6 +35,8 @@
    */
   protected function setUp() {
     parent::setUp();
+    $this->installSchema('system', ['router']);
+    $this->container->get('router.builder')->rebuild();
     $this->installMigrations('Drupal 6');
   }
 
diff --git a/core/modules/user/src/Entity/Role.php b/core/modules/user/src/Entity/Role.php
index 8421215..05d9040 100644
--- a/core/modules/user/src/Entity/Role.php
+++ b/core/modules/user/src/Entity/Role.php
@@ -186,4 +186,67 @@ public function preSave(EntityStorageInterface $storage) {
     }
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function calculateDependencies() {
+    parent::calculateDependencies();
+    // Load all permissions.
+    $permissions = \Drupal::service('user.permissions')->getPermissions();
+    foreach ($this->permissions as $permission) {
+      // @todo Remove this if() when https://www.drupal.org/node/2569741 is in.
+      if (isset($permissions[$permission])) {
+        // Depend on the module that is providing this permissions.
+        $this->addDependency('module', $permissions[$permission]['provider']);
+        // Depend on any other dependencies defined by permissions granted to
+        // this role.
+        if (!empty($permissions[$permission]['dependencies'])) {
+          foreach ($permissions[$permission]['dependencies'] as $type => $dependencies) {
+            foreach ($dependencies as $dependency) {
+              $this->addDependency($type, $dependency);
+            }
+          }
+        }
+      }
+    }
+    return $this->dependencies;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function onDependencyRemoval(array $dependencies) {
+    $changed = parent::onDependencyRemoval($dependencies);
+    // Load all permissions.
+    $permissions = \Drupal::service('user.permissions')->getPermissions();
+
+    // Merge the permission provider into the module dependency list.
+    array_walk($permissions, function(&$permission) {
+      $permission['dependencies']['module'][] = $permission['provider'];
+      $permission['dependencies']['module'] = array_unique($permission['dependencies']['module']);
+    });
+
+    $removed_permissions = [];
+    foreach ($dependencies as $type => $items) {
+      foreach ($items as $key => $dependency) {
+        // Get the dependency name, based on dependency type.
+        $name = in_array($type, ['config', 'content']) ? $dependency->getConfigDependencyName() : $dependency;
+        foreach ($this->permissions as $permission) {
+          if (!empty($permissions[$permission]['dependencies'][$type])) {
+            if (in_array($name, $permissions[$permission]['dependencies'][$type])) {
+              $removed_permissions[] = $permission;
+              break;
+            }
+          }
+        }
+      }
+    }
+    if ($removed_permissions) {
+      $this->permissions = array_diff($this->permissions, $removed_permissions);
+      $changed = TRUE;
+    }
+
+    return $changed;
+  }
+
 }
diff --git a/core/modules/user/src/PermissionHandler.php b/core/modules/user/src/PermissionHandler.php
index ac6e9bb..b3d109a 100644
--- a/core/modules/user/src/PermissionHandler.php
+++ b/core/modules/user/src/PermissionHandler.php
@@ -38,6 +38,11 @@
  *   # (optional) Boolean, when set to true a warning about site security will
  *   # be displayed on the Permissions page. Defaults to false.
  *   restrict access: false
+ *   # (optional) Dependency array following the same structure as the return
+ *   # config entities dependencies.
+ *   dependencies:
+ *     config:
+ *       - node.type.article
  *
  * # An array of callables used to generate dynamic permissions.
  * permission_callbacks:
@@ -46,6 +51,7 @@
  *   - Drupal\filter\FilterPermissions::permissions
  * @endcode
  *
+ * @see \Drupal\user\PermissionHandlerInterface::getPermissions()
  * @see filter.permissions.yml
  * @see \Drupal\filter\FilterPermissions
  * @see user_api
@@ -135,10 +141,9 @@ public function moduleProvidesPermissions($module_name) {
    * Builds all permissions provided by .permissions.yml files.
    *
    * @return array[]
-   *   Each return permission is an array with the following keys:
-   *   - title: The title of the permission.
-   *   - description: The description of the permission, defaults to NULL.
-   *   - provider: The provider of the permission.
+   *   An array with the same structure as ::getPermissions().
+   *
+   * @see \Drupal\user\PermissionHandlerInterface::getPermissions()
    */
   protected function buildPermissionsYaml() {
     $all_permissions = array();
@@ -198,10 +203,9 @@ protected function buildPermissionsYaml() {
    *   The permissions to be sorted.
    *
    * @return array[]
-   *   Each return permission is an array with the following keys:
-   *   - title: The title of the permission.
-   *   - description: The description of the permission, defaults to NULL.
-   *   - provider: The provider of the permission.
+   *   An array with the same structure as ::getPermissions().
+   *
+   * @see \Drupal\user\PermissionHandlerInterface::getPermissions()
    */
   protected function sortPermissions(array $all_permissions = array()) {
     // Get a list of all the modules providing permissions and sort by
diff --git a/core/modules/user/src/PermissionHandlerInterface.php b/core/modules/user/src/PermissionHandlerInterface.php
index 269af11..a0f3a3e 100644
--- a/core/modules/user/src/PermissionHandlerInterface.php
+++ b/core/modules/user/src/PermissionHandlerInterface.php
@@ -39,7 +39,20 @@
    *     permissions to have a clear, consistent security warning that is the
    *     same across the site. Use the 'description' key instead to provide any
    *     information that is specific to the permission you are defining.
+   *   - dependencies: (optional) An array of dependency entities used when
+   *     building this permission name, structured in the same way as the return
+   *     of ConfigEntityInterface::calculateDependencies(). For example if this
+   *     permission was generated as effect of the existence of node type
+   *     'article', then value of the dependency key is:
+   *     @code
+   *     'dependencies' => ['config' => ['node.type.article']]
+   *     @endcode
+   *     The module providing this permission doesn't have to be added as
+   *     dependency, because is automatically parsed, stored and retrieved from
+   *     the 'provider' key.
    *   - provider: (optional) The provider name of the permission.
+   *
+   * @see \Drupal\Core\Config\Entity\ConfigEntityInterface::calculateDependencies()
    */
   public function getPermissions();
 
diff --git a/core/modules/user/src/Tests/UserRoleDeleteTest.php b/core/modules/user/src/Tests/UserRoleDeleteTest.php
index 81396ac..b0a8f11 100644
--- a/core/modules/user/src/Tests/UserRoleDeleteTest.php
+++ b/core/modules/user/src/Tests/UserRoleDeleteTest.php
@@ -7,7 +7,11 @@
 
 namespace Drupal\user\Tests;
 
+use Drupal\Component\Utility\Unicode;
+use Drupal\filter\Entity\FilterFormat;
+use Drupal\node\Entity\NodeType;
 use Drupal\simpletest\KernelTestBase;
+use Drupal\user\Entity\Role;
 use Drupal\user\Entity\User;
 
 /**
@@ -73,7 +77,76 @@ public function testRoleDeleteUserRoleReferenceDelete() {
     // Check that user does not have role one.
     $this->assertFalse($user->hasRole('test_role_one'));
     $this->assertTrue($user->hasRole('test_role_two'));
+  }
+
+  /**
+   * Tests the removal of user role dependencies.
+   */
+  public function testDependenciesRemoval() {
+    $this->enableModules(['node', 'filter']);
+    $this->installSchema('system', ['router']);
+    $this->container->get('router.builder')->rebuild();
+
+    /** @var \Drupal\user\RoleInterface $role */
+    $role = Role::create([
+      'id' => $rid = Unicode::strtolower($this->randomMachineName()),
+      'label' => $this->randomString(),
+    ]);
+    $role->save();
+
+    /** @var \Drupal\node\NodeTypeInterface $node_type */
+    $node_type = NodeType::create([
+      'type' => Unicode::strtolower($this->randomMachineName()),
+      'name' => $this->randomString(),
+    ]);
+    $node_type->save();
 
+    // Create a new text format to be used by role $role.
+    $format = FilterFormat::create([
+      'format' => Unicode::strtolower($this->randomMachineName()),
+      'name' => $this->randomString(),
+    ]);
+    $format->save();
+
+    $permission_format = "use text format {$format->id()}";
+    $permission_node_type = "edit any {$node_type->id()} content";
+
+    // Grant $role with permission to use $format and edit $node_type.
+    $role
+      ->grantPermission($permission_format)
+      ->grantPermission($permission_node_type)
+      ->save();
+
+    // The role $role has the permissions to use $format and edit $node_type.
+    $role = Role::load($rid);
+    $this->assertTrue($role->hasPermission($permission_format));
+    $this->assertTrue($role->hasPermission($permission_node_type));
+
+    // The $role config entity exists before removing dependencies.
+    $this->assertNotNull($role = Role::load($rid));
+
+    // Remove the format.
+    $format->delete();
+
+    // The $role config entity exists after removing the config dependency.
+    if ($this->assertNotNull($role = Role::load($rid))) {
+      // The $format permission should have been revoked.
+      $this->assertFalse($role->hasPermission($permission_format));
+      $this->assertTrue($role->hasPermission($permission_node_type));
+    }
+
+    // We have to manually trigger the removal of configuration belonging to the
+    // module because KernelTestBase::disableModules() is not aware of this.
+    $this->container->get('config.manager')->uninstall('module', 'node');
+    // Disable the node module.
+    $this->disableModules(['node']);
+
+    // The $role config entity exists after removing the module dependency.
+    if ($this->assertNotNull($role = Role::load($rid))) {
+      // The $node_type permission should have been revoked too.
+      $this->assertFalse($role->hasPermission($permission_format));
+      $this->assertFalse($role->hasPermission($permission_node_type));
+    }
   }
 
 }
