diff --git a/core/modules/page_cache/src/Tests/PageCacheTest.php b/core/modules/page_cache/src/Tests/PageCacheTest.php
index 9194e65..64e4ee9 100644
--- a/core/modules/page_cache/src/Tests/PageCacheTest.php
+++ b/core/modules/page_cache/src/Tests/PageCacheTest.php
@@ -131,7 +131,7 @@ function testQueryParameterFormatRequests() {
     $this->assertRaw('{"content":"oh hai this is json"}', 'The correct Json response was returned.');
 
     // Enable REST support for nodes and hal+json.
-    \Drupal::service('module_installer')->install(['node', 'rest', 'hal']);
+    \Drupal::service('module_installer')->install(['node', 'rest', 'hal', 'basic_auth']);
     $this->drupalCreateContentType(['type' => 'article']);
     $node = $this->drupalCreateNode(['type' => 'article']);
     $node_uri = $node->urlInfo();
diff --git a/core/modules/rest/config/install/rest.settings.yml b/core/modules/rest/config/install/rest.settings.yml
index d3aa82b..2d8185e 100644
--- a/core/modules/rest/config/install/rest.settings.yml
+++ b/core/modules/rest/config/install/rest.settings.yml
@@ -1,50 +1,3 @@
-# Enable all methods on nodes.
-# You must install Hal and Basic_auth modules for this to work. Also, if you are
-# going to use Basic_auth in a production environment then you should consider
-# setting up SSL.
-# There are alternatives to Basic_auth in contrib such as OAuth module.
-resources:
-  entity:node:
-    GET:
-      supported_formats:
-        - hal_json
-      supported_auth:
-        - basic_auth
-    POST:
-      supported_formats:
-        - hal_json
-      supported_auth:
-        - basic_auth
-    PATCH:
-      supported_formats:
-        - hal_json
-      supported_auth:
-        - basic_auth
-    DELETE:
-      supported_formats:
-        - hal_json
-      supported_auth:
-        - basic_auth
-
-# Multiple formats and multiple authentication providers can be defined for a
-# resource:
-#
-# resources:
-#   entity:node:
-#     GET:
-#       supported_formats:
-#         - json
-#         - hal_json
-#         - xml
-#       supported_auth:
-#         - cookie
-#         - basic_auth
-#
-# hal_json is the only format supported for POST and PATCH methods.
-#
-# The full documentation is located at
-# https://www.drupal.org/documentation/modules/rest.
-
 # Set the domain for REST type and relation links.
 # If left blank, the site's domain will be used.
 link_domain: ~
diff --git a/core/modules/rest/config/optional/rest.resource.entity__node.yml b/core/modules/rest/config/optional/rest.resource.entity__node.yml
new file mode 100644
index 0000000..4561a2f
--- /dev/null
+++ b/core/modules/rest/config/optional/rest.resource.entity__node.yml
@@ -0,0 +1,28 @@
+id: entity__node
+plugin_id: 'entity:node'
+configuration:
+  GET:
+    supported_formats:
+      - hal_json
+    supported_auth:
+      - basic_auth
+  POST:
+    supported_formats:
+      - hal_json
+    supported_auth:
+      - basic_auth
+  PATCH:
+    supported_formats:
+      - hal_json
+    supported_auth:
+      - basic_auth
+  DELETE:
+    supported_formats:
+      - hal_json
+    supported_auth:
+      - basic_auth
+dependencies:
+  module:
+    - node
+    - basic_auth
+    - hal
diff --git a/core/modules/rest/config/schema/rest.schema.yml b/core/modules/rest/config/schema/rest.schema.yml
index 8014b31..215f9b9 100644
--- a/core/modules/rest/config/schema/rest.schema.yml
+++ b/core/modules/rest/config/schema/rest.schema.yml
@@ -1,15 +1,8 @@
 # Schema for the configuration files of the REST module.
-
 rest.settings:
   type: config_object
   label: 'REST settings'
   mapping:
-    resources:
-      type: sequence
-      label: 'Resources'
-      sequence:
-        type: rest_resource
-        label: 'Resource'
     link_domain:
       type: string
       label: 'Domain of the relation'
@@ -45,3 +38,17 @@ rest_request:
       sequence:
         type: string
         label: 'Authentication'
+
+rest.resource.*:
+  type: config_entity
+  label: 'REST resource config'
+  mapping:
+    id:
+      type: string
+      label: 'REST resource config ID'
+    plugin_id:
+      type: string
+      label: 'REST resource plugin id'
+    configuration:
+      type: rest_resource
+      label: 'REST resource configuration'
diff --git a/core/modules/rest/rest.install b/core/modules/rest/rest.install
index 4bca69b..4a153f9 100644
--- a/core/modules/rest/rest.install
+++ b/core/modules/rest/rest.install
@@ -5,6 +5,8 @@
  * Install, update and uninstall functions for the rest module.
  */
 
+use Drupal\rest\Entity\RestResourceConfig;
+
 /**
  * Implements hook_requirements().
  */
@@ -21,3 +23,20 @@ function rest_requirements($phase) {
   }
   return $requirements;
 }
+
+/**
+ * Install the REST config entity type and convert old settings-based config.
+ */
+function rest_update_8100() {
+  \Drupal::entityDefinitionUpdateManager()->installEntityType(\Drupal::entityTypeManager()->getDefinition('rest_resource_config'));
+  foreach (\Drupal::config('rest.settings')->get('resources') as $key => $resource) {
+    $resource = RestResourceConfig::create([
+      'id' => str_replace(':', '__', $key),
+      'configuration' => $resource,
+    ]);
+    $resource->save();
+  }
+  \Drupal::configFactory()->getEditable('rest.settings')
+    ->clear('resources')
+    ->save();
+}
diff --git a/core/modules/rest/rest.permissions.yml b/core/modules/rest/rest.permissions.yml
index 2ab7154..171a284 100644
--- a/core/modules/rest/rest.permissions.yml
+++ b/core/modules/rest/rest.permissions.yml
@@ -1,2 +1,5 @@
 permission_callbacks:
   - Drupal\rest\RestPermissions::permissions
+
+administer rest resources:
+  title: 'Administer REST resource configuration'
diff --git a/core/modules/rest/rest.services.yml b/core/modules/rest/rest.services.yml
index 6b613e3..207333f 100644
--- a/core/modules/rest/rest.services.yml
+++ b/core/modules/rest/rest.services.yml
@@ -1,3 +1,6 @@
+parameters:
+  rest.dependencies.auth: []
+  rest.dependencies.format: []
 services:
   plugin.manager.rest:
     class: Drupal\rest\Plugin\Type\ResourcePluginManager
@@ -24,9 +27,12 @@ services:
     arguments: ['@cache.default', '@entity.manager', '@module_handler', '@config.factory', '@request_stack']
   rest.resource_routes:
     class: Drupal\rest\Routing\ResourceRoutes
-    arguments: ['@plugin.manager.rest', '@config.factory', '@logger.channel.rest']
+    arguments: ['@plugin.manager.rest', '@entity_type.manager', '@logger.channel.rest']
     tags:
       - { name: 'event_subscriber' }
   logger.channel.rest:
     parent: logger.channel_base
     arguments: ['rest']
+  rest_resource.dependencies:
+    class: \Drupal\rest\Entity\ConfigDependencies
+    arguments: ['%rest.dependencies.format%', '%rest.dependencies.auth%']
diff --git a/core/modules/rest/src/Entity/ConfigDependencies.php b/core/modules/rest/src/Entity/ConfigDependencies.php
new file mode 100644
index 0000000..2c7feaf
--- /dev/null
+++ b/core/modules/rest/src/Entity/ConfigDependencies.php
@@ -0,0 +1,163 @@
+<?php
+
+namespace Drupal\rest\Entity;
+
+use Drupal\Component\Plugin\DependentPluginInterface;
+use Drupal\rest\RestResourceConfigInterface;
+
+/**
+ * Calculates rest resource config dependencies.
+ */
+class ConfigDependencies {
+
+  /**
+   * A list of available rest formats.
+   *
+   * @var string[]
+   */
+  protected $availableRestFormats;
+
+  /**
+   * A list of available authentications.
+   *
+   * @var string[]
+   */
+  protected $availableRestAuthentications;
+
+  /**
+   * Creates a new ConfigDependencies instance.
+   *
+   * @param string[] $available_rest_formats
+   *   A list of available rest formats.
+   * @param string[] $available_rest_authentications
+   *   A list of available authentications.
+   */
+  public function __construct(array $available_rest_formats, array $available_rest_authentications) {
+    $this->availableRestFormats = $available_rest_formats;
+    $this->availableRestAuthentications = $available_rest_authentications;
+  }
+
+  /**
+   * Calculates dependencies of a specific rest resource configuration.
+   *
+   * @param \Drupal\rest\RestResourceConfigInterface $rest_config
+   *   The rest configuration.
+   *
+   * @return string[][]
+   *   Dependencies keyed by dependency type.
+   *
+   * @see \Drupal\Core\Config\Entity\ConfigEntityInterface::calculateDependencies()
+   */
+  public function calculateDependencies(RestResourceConfigInterface $rest_config) {
+    // The dependency lists for authentication providers and formats
+    // generated on container build.
+    $dependencies = [];
+    foreach (array_keys($rest_config->get('configuration')) as $request_method) {
+      // Add dependencies based on the supported authentication providers.
+      foreach ($rest_config->getSupportedAuthenticationProviders($request_method) as $auth) {
+        if (isset($this->availableRestAuthentications[$auth])) {
+          $module_name = $this->availableRestAuthentications[$auth];
+          $dependencies['module'][] = $module_name;
+        }
+      }
+      // Add dependencies based on the supported authentication formats.
+      foreach ($rest_config->getSupportedFormats($request_method) as $format) {
+        if (isset($this->availableRestFormats[$format])) {
+          $module_name = $this->availableRestFormats[$format];
+          $dependencies['module'][] = $module_name;
+        }
+      }
+    }
+
+    if (($resource_plugin = $rest_config->getResourcePlugin()) && $resource_plugin instanceof DependentPluginInterface) {
+      $dependencies = array_merge($dependencies, $resource_plugin->calculateDependencies());
+    }
+
+    return $dependencies;
+  }
+
+  /**
+   * Informs the entity that entities it depends on will be deleted.
+   *
+   * @param \Drupal\rest\RestResourceConfigInterface $rest_config
+   *   The rest configuration.
+   * @param array $dependencies
+   *   An array of dependencies that will be deleted keyed by dependency type.
+   *   Dependency types are, for example, entity, module and theme.
+   *
+   * @return bool
+   *   TRUE if the entity has been changed as a result, FALSE if not.
+   *
+   * @see \Drupal\Core\Config\Entity\ConfigEntityInterface::onDependencyRemoval()
+   */
+  public function onDependencyRemoval(RestResourceConfigInterface $rest_config, array $dependencies) {
+    $changed = FALSE;
+    // Only module-related dependencies can be fixed. All other types of
+    // dependencies cannot, because they were not generated based on supported
+    // authentication providers or formats.
+    if (isset($dependencies['module'])) {
+      // Try to fix dependencies.
+      $removed_auth = [];
+      $removed_formats = [];
+      foreach ($dependencies['module'] as $dep_module) {
+        // Check if the removed dependency module contained an authentication
+        // provider.
+        foreach ($this->availableRestAuthentications as $auth => $auth_module) {
+          if ($dep_module != $auth_module) {
+            continue;
+          }
+          $removed_auth[] = $auth;
+        }
+        // Check if the removed dependency module contained a format.
+        foreach ($this->availableRestFormats as $format => $format_module) {
+          if ($dep_module != $format_module) {
+            continue;
+          }
+          $removed_formats[] = $format;
+        }
+      }
+      $configuration = $rest_config->get('configuration');
+      if (!empty($removed_auth) || !empty($removed_formats)) {
+        // Try to fix dependency problems by removing affected
+        // authentication providers and formats.
+        foreach (array_keys($rest_config->get('configuration')) as $request_method) {
+          foreach ($removed_formats as $format) {
+            if ($rest_config->supportsFormat($request_method, $format)) {
+              $rest_config->removeSupportedFormat($request_method, $format);
+            }
+          }
+          foreach ($removed_auth as $auth) {
+            if ($rest_config->hasSupportForAuthenticationProvider($request_method, $auth)) {
+              $rest_config->removeSupportedAuthenticationProvider($request_method, $auth);
+            }
+          }
+          if (!$rest_config->supportsAuthenticationProviders($request_method)) {
+            // Remove the key if there are no more authentication providers
+            // supported by this request method.
+            unset($configuration[$request_method]['supported_auth']);
+          }
+          if (!$rest_config->hasSupportedFormats($request_method)) {
+            // Remove the key if there are no more formats supported by this
+            // request method.
+            unset($configuration[$request_method]['supported_formats']);
+          }
+          if (empty($configuration[$request_method])) {
+            // Remove the request method altogether if it no longer has any
+            // supported authentication providers or formats.
+            unset($configuration[$request_method]);
+          }
+        }
+      }
+      if (!empty($configuration)) {
+        // Only mark the dependencies problems as fixed if there is any
+        // configuration left.
+        $changed = TRUE;
+      }
+    }
+    // If the dependency problems are not marked as fixed at this point they
+    // should be related to the resource plugin and the config entity should
+    // be deleted.
+    return $changed;
+  }
+
+}
diff --git a/core/modules/rest/src/Entity/RestResourceConfig.php b/core/modules/rest/src/Entity/RestResourceConfig.php
new file mode 100644
index 0000000..8d24af4
--- /dev/null
+++ b/core/modules/rest/src/Entity/RestResourceConfig.php
@@ -0,0 +1,308 @@
+<?php
+
+namespace Drupal\rest\Entity;
+
+use Drupal\Core\Config\Entity\ConfigEntityBase;
+use Drupal\Core\Entity\Entity;
+use Drupal\Core\Plugin\DefaultSingleLazyPluginCollection;
+use Drupal\rest\RestResourceConfigInterface;
+
+/**
+ * Defines a RestResourceConfig configuration entity class.
+ *
+ * @ConfigEntityType(
+ *   id = "rest_resource_config",
+ *   label = @Translation("REST resource config"),
+ *   config_prefix = "resource",
+ *   admin_permission = "administer rest resources",
+ *   label_callback = "getLabelFromPlugin",
+ *   entity_keys = {
+ *     "id" = "id"
+ *   },
+ *   config_export = {
+ *     "id",
+ *     "plugin_id",
+ *     "configuration"
+ *   }
+ * )
+ */
+class RestResourceConfig extends ConfigEntityBase implements RestResourceConfigInterface {
+
+  /**
+   * The REST resource config id.
+   *
+   * @var string
+   */
+  protected $id;
+
+  /**
+   * The REST resource plugin id.
+   *
+   * @var string
+   */
+  protected $plugin_id;
+
+  /**
+   * The REST resource configuration.
+   *
+   * @var array
+   */
+  protected $configuration;
+
+  /**
+   * The rest resource plugin manager.
+   *
+   * @var \Drupal\Component\Plugin\PluginManagerInterface
+   */
+  protected $pluginManager;
+
+  /**
+   * {@inheritdoc}
+   */
+  public function __construct(array $values, $entity_type) {
+    parent::__construct($values, $entity_type);
+    // The config entity id looks like the plugin id but uses __ instead of :
+    // because : is not valid for config entities.
+    if (!isset($this->plugin_id) && isset($this->id)) {
+      // Generate plugin_id on first entity creation.
+      $this->plugin_id = str_replace('__', ':', $this->id);
+    }
+  }
+
+  /**
+   * The label callback for this configuration entity.
+   *
+   * @return string The label.
+   */
+  protected function getLabelFromPlugin() {
+    $plugin_definition = $this->getResourcePluginManager()
+      ->getDefinition(['id' => $this->getResourcePluginID()]);
+    return $plugin_definition['label'];
+  }
+
+  /**
+   * Returns the resource plugin manager.
+   *
+   * @return \Drupal\Component\Plugin\PluginManagerInterface
+   */
+  protected function getResourcePluginManager() {
+    if (!isset($this->pluginManager)) {
+      $this->pluginManager = \Drupal::service('plugin.manager.rest');
+    }
+    return $this->pluginManager;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getResourcePluginID() {
+    return $this->plugin_id;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getResourcePlugin() {
+    return $this->getPluginCollections()['resource']->get($this->getResourcePluginID());
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function isRequestMethodEnabled($method) {
+    $method = $this->normalizeRestMethod($method);
+    return isset($this->configuration[$method]);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getSupportedAuthenticationProviders($method) {
+    $method = $this->normalizeRestMethod($method);
+    if ($this->isRequestMethodEnabled($method) && isset($this->configuration[$method]['supported_auth'])) {
+      return $this->configuration[$method]['supported_auth'];
+    }
+    return [];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function hasSupportForAuthenticationProvider($method, $auth) {
+    $method = $this->normalizeRestMethod($method);
+    return $this->supportsAuthenticationProviders($method)
+           && in_array($auth, $this->configuration[$method]['supported_auth']);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function supportsAuthenticationProviders($method) {
+    $method = $this->normalizeRestMethod($method);
+    return $this->isRequestMethodEnabled($method)
+           && isset($this->configuration[$method]['supported_auth'])
+           && !empty($this->configuration[$method]['supported_auth']);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function addSupportedAuthenticationProvider($method, $auth) {
+    $method = $this->normalizeRestMethod($method);
+    if (!$this->isRequestMethodEnabled($method)) {
+      $this->configuration[$method] = ['supported_auth' => []];
+    }
+    if (!isset($this->configuration[$method]['supported_auth'])){
+      $this->configuration[$method]['supported_auth'] = [];
+    }
+    if (!in_array($auth, $this->configuration[$method]['supported_auth'])) {
+      $this->configuration[$method]['supported_auth'][] = $auth;
+    }
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function removeSupportedAuthenticationProvider($method, $auth) {
+    $method = $this->normalizeRestMethod($method);
+    if ($this->supportsAuthenticationProviders($method)) {
+      $new_auth = array_filter($this->configuration[$method]['supported_auth'], function ($val) use ($auth) {
+        return ($val != $auth);
+      });
+      $this->configuration[$method]['supported_auth'] = $new_auth;
+    }
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getSupportedFormats($method) {
+    $method = $this->normalizeRestMethod($method);
+    if ($this->isRequestMethodEnabled($method) && isset($this->configuration[$method]['supported_formats'])) {
+      return $this->configuration[$method]['supported_formats'];
+    }
+    return [];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function supportsFormat($method, $format) {
+    $method = $this->normalizeRestMethod($method);
+    return $this->hasSupportedFormats($method)
+           && in_array($format, $this->configuration[$method]['supported_formats']);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function hasSupportedFormats($method) {
+    $method = $this->normalizeRestMethod($method);
+    return $this->isRequestMethodEnabled($method)
+           && isset($this->configuration[$method]['supported_formats'])
+           && !empty($this->configuration[$method]['supported_formats']);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function addSupportedFormat($method, $format) {
+    $method = $this->normalizeRestMethod($method);
+    if (!$this->isRequestMethodEnabled($method)) {
+      $this->configuration[$method] = ['supported_formats' => []];
+    }
+    if (!isset($this->configuration[$method]['supported_formats'])){
+      $this->configuration[$method]['supported_formats'] = [];
+    }
+    if (!in_array($format, $this->configuration[$method]['supported_formats'])) {
+      $this->configuration[$method]['supported_formats'][] = $format;
+    }
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function removeSupportedFormat($method, $format) {
+    $method = $this->normalizeRestMethod($method);
+    if ($this->hasSupportedFormats($method)){
+      $new_auth = array_filter($this->configuration[$method]['supported_formats'], function ($val) use ($format) {
+        return ($val != $format);
+      });
+      $this->configuration[$method]['supported_formats'] = $new_auth;
+    }
+    return $this;
+  }
+
+  /**
+   * Returns the plugin collections used by this entity.
+   *
+   * @return \Drupal\Component\Plugin\LazyPluginCollection[]
+   *   An array of plugin collections, keyed by the property name they use to
+   *   store their configuration.
+   */
+  public function getPluginCollections() {
+    return [
+      'resource' => new DefaultSingleLazyPluginCollection($this->getResourcePluginManager(), $this->getResourcePluginID(), [])
+    ];
+  }
+
+  /**
+   * (@inheritdoc)
+   */
+  public function calculateDependencies() {
+    parent::calculateDependencies();
+
+    foreach ($this->getRestResourceDependencies()->calculateDependencies($this) as $type => $dependencies) {
+      foreach ($dependencies as $dependency) {
+        $this->addDependency($type, $dependency);
+      }
+    }
+    return $this->dependencies;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function onDependencyRemoval(array $dependencies) {
+    $parent = parent::onDependencyRemoval($dependencies);
+
+    // If the dependency problems are not marked as fixed at this point they
+    // should be related to the resource plugin and the config entity should
+    // be deleted.
+    $changed = $this->getRestResourceDependencies()->onDependencyRemoval($this, $dependencies);
+    return $parent || $changed;
+  }
+
+  /**
+   * Returns the REST resource dependencies.
+   *
+   * @return \Drupal\rest\Entity\ConfigDependencies
+   */
+  protected function getRestResourceDependencies() {
+    return \Drupal::service('rest_resource.dependencies');
+  }
+
+  /**
+   * Normalizes the method to upper case and check validity.
+   *
+   * @param string $method
+   *   The request method.
+   *
+   * @return string
+   *   The normalised request method.
+   *
+   * @throws \InvalidArgumentException
+   *   If the method is not supported.
+   */
+  protected function normalizeRestMethod($method) {
+    $valid_methods = ['GET', 'POST', 'PATCH', 'DELETE'];
+    $normalised_method = strtoupper($method);
+    if (!in_array($normalised_method, $valid_methods)) {
+      throw new \InvalidArgumentException('The method is not supported.');
+    }
+    return $normalised_method;
+  }
+}
diff --git a/core/modules/rest/src/Plugin/ResourceBase.php b/core/modules/rest/src/Plugin/ResourceBase.php
index 33cb3aa..549ac54 100644
--- a/core/modules/rest/src/Plugin/ResourceBase.php
+++ b/core/modules/rest/src/Plugin/ResourceBase.php
@@ -194,8 +194,6 @@ protected function getBaseRoute($canonical_path, $method) {
 
     $route = new Route($canonical_path, array(
       '_controller' => 'Drupal\rest\RequestHandler::handle',
-      // Pass the resource plugin ID along as default property.
-      '_plugin' => $this->pluginId,
     ), array(
       '_permission' => "restful $lower_method $this->pluginId",
     ),
diff --git a/core/modules/rest/src/Plugin/rest/resource/EntityResource.php b/core/modules/rest/src/Plugin/rest/resource/EntityResource.php
index 6ec5f26..715d0fd 100644
--- a/core/modules/rest/src/Plugin/rest/resource/EntityResource.php
+++ b/core/modules/rest/src/Plugin/rest/resource/EntityResource.php
@@ -2,10 +2,14 @@
 
 namespace Drupal\rest\Plugin\rest\resource;
 
+use Drupal\Component\Plugin\DependentPluginInterface;
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Entity\EntityStorageException;
+use Drupal\Core\Entity\EntityTypeManagerInterface;
 use Drupal\rest\Plugin\ResourceBase;
 use Drupal\rest\ResourceResponse;
+use Psr\Log\LoggerInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
 use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
 use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
 use Symfony\Component\HttpKernel\Exception\HttpException;
@@ -26,7 +30,49 @@
  *   }
  * )
  */
-class EntityResource extends ResourceBase {
+class EntityResource extends ResourceBase implements DependentPluginInterface {
+
+  /**
+   * The entity type targeted by this resource.
+   *
+   * @var \Drupal\Core\Entity\EntityTypeInterface
+   */
+  protected $entityType;
+
+  /**
+   * Constructs a Drupal\rest\Plugin\rest\resource\EntityResource object.
+   *
+   * @param array $configuration
+   *   A configuration array containing information about the plugin instance.
+   * @param string $plugin_id
+   *   The plugin_id for the plugin instance.
+   * @param mixed $plugin_definition
+   *   The plugin implementation definition.
+   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
+   *   The entity type manager
+   * @param array $serializer_formats
+   *   The available serialization formats.
+   * @param \Psr\Log\LoggerInterface $logger
+   *   A logger instance.
+   */
+  public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeManagerInterface $entity_type_manager,  $serializer_formats, LoggerInterface $logger) {
+    parent::__construct($configuration, $plugin_id, $plugin_definition, $serializer_formats, $logger);
+    $this->entityType = $entity_type_manager->getDefinition($plugin_definition['entity_type']);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
+    return new static(
+      $configuration,
+      $plugin_id,
+      $plugin_definition,
+      $container->get('entity_type.manager'),
+      $container->getParameter('serializer.formats'),
+      $container->get('logger.factory')->get('rest')
+    );
+  }
 
   /**
    * Responds to entity GET requests.
@@ -245,4 +291,13 @@ protected function getBaseRoute($canonical_path, $method) {
     return $route;
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function calculateDependencies() {
+    if (isset($this->entityType)) {
+      return ['module' => [$this->entityType->getProvider()]];
+    }
+  }
+
 }
diff --git a/core/modules/rest/src/RequestHandler.php b/core/modules/rest/src/RequestHandler.php
index 8e0cd74..3d4d294 100644
--- a/core/modules/rest/src/RequestHandler.php
+++ b/core/modules/rest/src/RequestHandler.php
@@ -2,10 +2,13 @@
 
 namespace Drupal\rest;
 
+use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
+use Drupal\Core\Entity\EntityStorageInterface;
 use Drupal\Core\Render\RenderContext;
 use Drupal\Core\Routing\RouteMatchInterface;
 use Symfony\Component\DependencyInjection\ContainerAwareInterface;
 use Symfony\Component\DependencyInjection\ContainerAwareTrait;
+use Symfony\Component\DependencyInjection\ContainerInterface;
 use Symfony\Component\HttpFoundation\Request;
 use Symfony\Component\HttpFoundation\Response;
 use Symfony\Component\HttpKernel\Exception\HttpException;
@@ -16,11 +19,35 @@
 /**
  * Acts as intermediate request forwarder for resource plugins.
  */
-class RequestHandler implements ContainerAwareInterface {
+class RequestHandler implements ContainerAwareInterface, ContainerInjectionInterface {
 
   use ContainerAwareTrait;
 
   /**
+   * The resource configuration storage.
+   *
+   * @var \Drupal\Core\Entity\EntityStorageInterface
+   */
+  protected $resourceStorage;
+
+  /**
+   * Creates a new RequestHandler instance.
+   *
+   * @param \Drupal\Core\Entity\EntityStorageInterface $entity_storage
+   *   The resource configuration storage.
+   */
+  public function __construct(EntityStorageInterface $entity_storage) {
+    $this->resourceStorage = $entity_storage;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container) {
+    return new static($container->get('entity_type.manager')->getStorage('rest_resource_config'));
+  }
+
+  /**
    * Handles a web API request.
    *
    * @param \Drupal\Core\Routing\RouteMatchInterface $route_match
@@ -32,13 +59,12 @@ class RequestHandler implements ContainerAwareInterface {
    *   The response object.
    */
   public function handle(RouteMatchInterface $route_match, Request $request) {
-
-    $plugin = $route_match->getRouteObject()->getDefault('_plugin');
     $method = strtolower($request->getMethod());
 
-    $resource = $this->container
-      ->get('plugin.manager.rest')
-      ->createInstance($plugin);
+    $resource_config_id = $route_match->getRouteObject()->getDefault('_rest_resource_config');
+    /** @var \Drupal\rest\RestResourceConfigInterface $resource_config */
+    $resource_config = $this->resourceStorage->load($resource_config_id);
+    $resource = $resource_config->getResourcePlugin();
 
     // Deserialize incoming data if available.
     $serializer = $this->container->get('serializer');
@@ -51,9 +77,8 @@ public function handle(RouteMatchInterface $route_match, Request $request) {
       // formats are configured allow all and hope that the serializer knows the
       // format. If the serializer cannot handle it an exception will be thrown
       // that bubbles up to the client.
-      $config = $this->container->get('config.factory')->get('rest.settings')->get('resources');
-      $method_settings = $config[$plugin][$request->getMethod()];
-      if (empty($method_settings['supported_formats']) || in_array($format, $method_settings['supported_formats'])) {
+      $request_method = $request->getMethod();
+      if (!$resource_config->hasSupportedFormats($request_method) || $resource_config->supportsFormat($request_method, $format)) {
         $definition = $resource->getPluginDefinition();
         $class = $definition['serialization_class'];
         try {
@@ -99,7 +124,7 @@ public function handle(RouteMatchInterface $route_match, Request $request) {
     }
 
     return $response instanceof ResourceResponse ?
-      $this->renderResponse($request, $response, $serializer, $format) :
+      $this->renderResponse($request, $response, $serializer, $format, $resource_config) :
       $response;
   }
 
@@ -130,6 +155,8 @@ public function csrfToken() {
    *   The serializer to use.
    * @param string $format
    *   The response format.
+   * @param \Drupal\rest\RestResourceConfigInterface $resource_config
+   *   The resource config.
    *
    * @return \Drupal\rest\ResourceResponse
    *   The altered response.
@@ -137,7 +164,7 @@ public function csrfToken() {
    * @todo Add test coverage for language negotiation contexts in
    *   https://www.drupal.org/node/2135829.
    */
-  protected function renderResponse(Request $request, ResourceResponse $response, SerializerInterface $serializer, $format) {
+  protected function renderResponse(Request $request, ResourceResponse $response, SerializerInterface $serializer, $format, RestResourceConfigInterface $resource_config) {
     $data = $response->getResponseData();
     $context = new RenderContext();
     $output = $this->container->get('renderer')
@@ -150,10 +177,8 @@ protected function renderResponse(Request $request, ResourceResponse $response,
     }
 
     $response->headers->set('Content-Type', $request->getMimeType($format));
-    // Add rest settings config's cache tags.
-    $response->addCacheableDependency($this->container->get('config.factory')
-      ->get('rest.settings'));
-
+    // Add rest config's cache tags.
+    $response->addCacheableDependency($resource_config);
     return $response;
   }
 
diff --git a/core/modules/rest/src/RestPermissions.php b/core/modules/rest/src/RestPermissions.php
index 57e95e4..473c192 100644
--- a/core/modules/rest/src/RestPermissions.php
+++ b/core/modules/rest/src/RestPermissions.php
@@ -2,8 +2,8 @@
 
 namespace Drupal\rest;
 
-use Drupal\Core\Config\ConfigFactoryInterface;
 use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
+use Drupal\Core\Entity\EntityTypeManagerInterface;
 use Drupal\rest\Plugin\Type\ResourcePluginManager;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
@@ -20,30 +20,30 @@ class RestPermissions implements ContainerInjectionInterface {
   protected $restPluginManager;
 
   /**
-   * The config factory.
+   * The REST resource config storage.
    *
-   * @var \Drupal\Core\Config\ConfigFactoryInterface
+   * @var \Drupal\Core\Entity\EntityManagerInterface
    */
-  protected $configFactory;
+  protected $resourceConfigStorage;
 
   /**
    * Constructs a new RestPermissions instance.
    *
    * @param \Drupal\rest\Plugin\Type\ResourcePluginManager $rest_plugin_manager
    *   The rest resource plugin manager.
-   * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
-   *   The config factory.
+   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
+   *   The entity type manager.
    */
-  public function __construct(ResourcePluginManager $rest_plugin_manager, ConfigFactoryInterface $config_factory) {
+  public function __construct(ResourcePluginManager $rest_plugin_manager, EntityTypeManagerInterface $entity_type_manager) {
     $this->restPluginManager = $rest_plugin_manager;
-    $this->configFactory = $config_factory;
+    $this->resourceConfigStorage = $entity_type_manager->getStorage('rest_resource_config');
   }
 
   /**
    * {@inheritdoc}
    */
   public static function create(ContainerInterface $container) {
-    return new static($container->get('plugin.manager.rest'), $container->get('config.factory'));
+    return new static($container->get('plugin.manager.rest'), $container->get('entity_type.manager'));
   }
 
   /**
@@ -53,12 +53,11 @@ public static function create(ContainerInterface $container) {
    */
   public function permissions() {
     $permissions = [];
-    $resources = $this->configFactory->get('rest.settings')->get('resources');
-    if ($resources && $enabled = array_intersect_key($this->restPluginManager->getDefinitions(), $resources)) {
-      foreach ($enabled as $id => $resource) {
-        $plugin = $this->restPluginManager->createInstance($id);
-        $permissions = array_merge($permissions, $plugin->permissions());
-      }
+    /** @var \Drupal\rest\RestResourceConfigInterface[] $resource_configs */
+    $resource_configs = $this->resourceConfigStorage->loadMultiple();
+    foreach ($resource_configs as $resource_config) {
+      $plugin = $resource_config->getResourcePlugin();
+      $permissions = array_merge($permissions, $plugin->permissions());
     }
     return $permissions;
   }
diff --git a/core/modules/rest/src/RestResourceConfigInterface.php b/core/modules/rest/src/RestResourceConfigInterface.php
new file mode 100644
index 0000000..29f2776
--- /dev/null
+++ b/core/modules/rest/src/RestResourceConfigInterface.php
@@ -0,0 +1,165 @@
+<?php
+
+namespace Drupal\rest;
+
+use Drupal\Core\Config\Entity\ConfigEntityInterface;
+use Drupal\Core\Entity\EntityWithPluginCollectionInterface;
+
+/**
+ * Defines a configuration entity to store enabled REST resources.
+ */
+interface RestResourceConfigInterface extends ConfigEntityInterface, EntityWithPluginCollectionInterface {
+
+  /**
+   * Retrieves the REST resource plugin id.
+   *
+   * @return string The plugin id
+   */
+  public function getResourcePluginID();
+
+  /**
+   * Retrieves the REST resource plugin.
+   *
+   * @return \Drupal\rest\Plugin\ResourceInterface
+   *   The resource plugin
+   */
+  public function getResourcePlugin();
+
+  /**
+   * Denotes whether a given request method is enabled for this resource.
+   *
+   * @param string $method
+   *   The request method.
+   * @return bool
+   */
+  public function isRequestMethodEnabled($method);
+
+  /**
+   * Retrieves a list of supported authentication mechanisms
+   *   for a specific request method.
+   *
+   * @param string $method
+   *   The request method e.g GET or POST.
+   *
+   * @return string[]
+   *   An array of supported authentication provider plugin id's
+   */
+  public function getSupportedAuthenticationProviders($method);
+
+  /**
+   * Denotes whether the given request method supports
+   *   the specified authentication provider on this resource
+   *
+   * @param string $method
+   *   The request method e.g GET or POST.
+   * @param string $auth
+   *   An authentication provider plugin id.
+   *
+   * @return bool
+   */
+  public function hasSupportForAuthenticationProvider($method, $auth);
+
+  /**
+   * Denotes whether the given request method
+   *   supports at least one authentication provider.
+   *
+   * @param string $method
+   *   The request method e.g GET or POST.
+   *
+   * @return bool
+   */
+  public function supportsAuthenticationProviders($method);
+
+  /**
+   * Add the specified authentication provider to
+   *   the list of supported authentication providers
+   *   for the given request method.
+   *
+   * @param string $method
+   *   The request method e.g GET or POST.
+   * @param string $auth
+   *   An authentication provider plugin id.
+   *
+   * @return $this
+   */
+  public function addSupportedAuthenticationProvider($method, $auth);
+
+  /**
+   *  Remove the specified authentication provider from
+   *   the list of supported authentication providers
+   *   for the given request method.
+   *
+   * @param string $method
+   *   The request method e.g GET or POST.
+   * @param string $auth
+   *   An authentication provider plugin id.
+   *
+   * @return $this
+   */
+  public function removeSupportedAuthenticationProvider($method, $auth);
+
+  /**
+   * Retrieves a list of supported formats for a specific request method.
+   *
+   * @param string $method
+   *   The request method e.g GET or POST.
+   *
+   * @return string[]
+   *   An array of supported format plugin id's.
+   */
+  public function getSupportedFormats($method);
+
+  /**
+   * Denotes whether the given request method supports
+   *   the specified format on this resource
+   *
+   * @param string $method
+   *   The request method e.g GET or POST.
+   * @param string $format
+   *   A format plugin id.
+   *
+   * @return bool
+   */
+  public function supportsFormat($method, $format);
+
+  /**
+   * Denotes whether the given request method supports at least one format.
+   *
+   * @param string $method
+   *   The request method e.g GET or POST.
+   *
+   * @return bool
+   */
+  public function hasSupportedFormats($method);
+
+  /**
+   * Adds the specified format.
+   *
+   * This format is added to the list of supported authentication providers for
+   * the given request method.
+   *
+   * @param string $method
+   *   The request method e.g GET or POST.
+   * @param string $format
+   *   A format plugin id.
+   *
+   * @return $this
+   */
+  public function addSupportedFormat($method, $format);
+
+  /**
+   * Removes the specified format from.
+   *
+   * This format is removed from the list of supported authentication providers
+   * for the given request method.
+   *
+   * @param string $method
+   *   The request method e.g GET or POST.
+   * @param string $format
+   *   A format plugin id.
+   *
+   * @return $this
+   */
+  public function removeSupportedFormat($method, $format);
+
+}
diff --git a/core/modules/rest/src/RestServiceProvider.php b/core/modules/rest/src/RestServiceProvider.php
new file mode 100644
index 0000000..190fac1
--- /dev/null
+++ b/core/modules/rest/src/RestServiceProvider.php
@@ -0,0 +1,60 @@
+<?php
+
+namespace Drupal\rest;
+
+use Drupal\Core\DependencyInjection\ContainerBuilder;
+use Drupal\Core\DependencyInjection\ServiceProviderInterface;
+
+/**
+ * Registers rest dependencies in the container.
+ */
+class RestServiceProvider implements ServiceProviderInterface {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function register(ContainerBuilder $container) {
+    $auth = [];
+    // Build a dependency list for available authentication providers.
+    foreach ($container->findTaggedServiceIds('authentication_provider') as $service_id => $service_tags) {
+      $service_def = $container->findDefinition($service_id);
+      $service_class = $service_def->getClass();
+      if (!empty($service_class)) {
+        // Extract module name based on class namespace.
+        list($namespace_base, $module_name) = explode('\\', $service_class);
+        if (!empty($namespace_base) && ucfirst(strtolower($namespace_base)) == 'Drupal') {
+          // Remove the 'authentication.' prefix from the provider ID.
+          $provider_id = substr($service_id, 15);
+          $auth[$provider_id] = $module_name;
+        }
+      }
+    }
+    if (!empty($auth)) {
+      // Register the dependency list in the container.
+      $container->setParameter('rest.dependencies.auth', $auth);
+    }
+
+    $formats = [];
+    // Build a dependency list for available formats.
+    foreach ($container->findTaggedServiceIds('encoder') as $service_id => $service_tags) {
+      $service_def = $container->findDefinition($service_id);
+      $service_class = $service_def->getClass();
+      if (!empty($service_class)) {
+        // Extract module name based on class namespace.
+        list($namespace_base, $module_name) = explode('\\', $service_class);
+        if (!empty($namespace_base) && ucfirst(strtolower($namespace_base)) == 'Drupal') {
+          foreach ($service_tags as $service_tag) {
+            if (isset($service_tag['format'])) {
+              $format = $service_tag['format'];
+              $formats[$format] = $module_name;
+            }
+          }
+        }
+      }
+    }
+    if (!empty($formats)) {
+      // Register the dependency list in the container.
+      $container->setParameter('rest.dependencies.format', $formats);
+    }
+  }
+}
diff --git a/core/modules/rest/src/Routing/ResourceRoutes.php b/core/modules/rest/src/Routing/ResourceRoutes.php
index e88f18b..74968fc 100644
--- a/core/modules/rest/src/Routing/ResourceRoutes.php
+++ b/core/modules/rest/src/Routing/ResourceRoutes.php
@@ -2,9 +2,10 @@
 
 namespace Drupal\rest\Routing;
 
-use Drupal\Core\Config\ConfigFactoryInterface;
+use Drupal\Core\Entity\EntityTypeManagerInterface;
 use Drupal\Core\Routing\RouteSubscriberBase;
 use Drupal\rest\Plugin\Type\ResourcePluginManager;
+use Drupal\rest\RestResourceConfigInterface;
 use Psr\Log\LoggerInterface;
 use Symfony\Component\Routing\RouteCollection;
 
@@ -21,11 +22,11 @@ class ResourceRoutes extends RouteSubscriberBase {
   protected $manager;
 
   /**
-   * The Drupal configuration factory.
+   * The REST resource config storage.
    *
-   * @var \Drupal\Core\Config\ConfigFactoryInterface
+   * @var \Drupal\Core\Entity\EntityManagerInterface
    */
-  protected $config;
+  protected $resourceConfigStorage;
 
   /**
    * A logger instance.
@@ -39,14 +40,14 @@ class ResourceRoutes extends RouteSubscriberBase {
    *
    * @param \Drupal\rest\Plugin\Type\ResourcePluginManager $manager
    *   The resource plugin manager.
-   * @param \Drupal\Core\Config\ConfigFactoryInterface $config
-   *   The configuration factory holding resource settings.
+   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
+   *   The entity type manager
    * @param \Psr\Log\LoggerInterface $logger
    *   A logger instance.
    */
-  public function __construct(ResourcePluginManager $manager, ConfigFactoryInterface $config, LoggerInterface $logger) {
+  public function __construct(ResourcePluginManager $manager, EntityTypeManagerInterface $entity_type_manager, LoggerInterface $logger) {
     $this->manager = $manager;
-    $this->config = $config;
+    $this->resourceConfigStorage = $entity_type_manager->getStorage('rest_resource_config');
     $this->logger = $logger;
   }
 
@@ -58,56 +59,68 @@ public function __construct(ResourcePluginManager $manager, ConfigFactoryInterfa
    * @return array
    */
   protected function alterRoutes(RouteCollection $collection) {
-    $routes = array();
-
-    // Silently ignore resources that are in the settings but are not defined on
-    // the plugin manager currently. That avoids exceptions when REST module is
-    // enabled before another module that provides the resource plugin specified
-    // in the settings.
-    // @todo Remove in https://www.drupal.org/node/2308745
-    $resources = $this->config->get('rest.settings')->get('resources') ?: array();
-    $enabled_resources = array_intersect_key($resources, $this->manager->getDefinitions());
-    if (count($resources) != count($enabled_resources)) {
-      trigger_error('rest.settings lists resources relying on the following missing plugins: ' . implode(', ', array_keys(array_diff_key($resources, $enabled_resources))));
+    // Iterate over all enabled REST resource configs.
+    /** @var \Drupal\rest\RestResourceConfigInterface[] $resource_configs */
+    $resource_configs = $this->resourceConfigStorage->loadMultiple();
+    // Iterate over all enabled resource plugins.
+    foreach ($resource_configs as $resource_config) {
+      $resource_routes = $this->getRoutesForResourceConfig($resource_config);
+      $collection->addCollection($resource_routes);
     }
+  }
 
-    // Iterate over all enabled resource plugins.
-    foreach ($enabled_resources as $id => $enabled_methods) {
-      $plugin = $this->manager->createInstance($id);
-      foreach ($plugin->routes() as $name => $route) {
-        // @todo: Are multiple methods possible here?
-        $methods = $route->getMethods();
-        // Only expose routes where the method is enabled in the configuration.
-        if ($methods && ($method = $methods[0]) && $method && isset($enabled_methods[$method])) {
-          $route->setRequirement('_access_rest_csrf', 'TRUE');
-
-          // Check that authentication providers are defined.
-          if (empty($enabled_methods[$method]['supported_auth']) || !is_array($enabled_methods[$method]['supported_auth'])) {
-            $this->logger->error('At least one authentication provider must be defined for resource @id', array(':id' => $id));
-            continue;
-          }
-
-          // Check that formats are defined.
-          if (empty($enabled_methods[$method]['supported_formats']) || !is_array($enabled_methods[$method]['supported_formats'])) {
-            $this->logger->error('At least one format must be defined for resource @id', array(':id' => $id));
-            continue;
-          }
-
-          // If the route has a format requirement, then verify that the
-          // resource has it.
-          $format_requirement = $route->getRequirement('_format');
-          if ($format_requirement && !in_array($format_requirement, $enabled_methods[$method]['supported_formats'])) {
-            continue;
-          }
-
-          // The configuration seems legit at this point, so we set the
-          // authentication provider and add the route.
-          $route->setOption('_auth', $enabled_methods[$method]['supported_auth']);
-          $routes["rest.$name"] = $route;
-          $collection->add("rest.$name", $route);
+  /**
+   * Provides all routes for a given REST resource config.
+   *
+   * This method determines where a resource is reachable, what path
+   * replacements are used, the required HTTP method for the operation etc.
+   *
+   * @param \Drupal\rest\RestResourceConfigInterface $rest_resource_config
+   *   The rest resource config.
+   *
+   * @return \Symfony\Component\Routing\RouteCollection
+   *   The route collection.
+   */
+  protected function getRoutesForResourceConfig(RestResourceConfigInterface $rest_resource_config) {
+    $plugin = $rest_resource_config->getResourcePlugin();
+    $collection = new RouteCollection();
+
+    foreach ($plugin->routes() as $name => $route) {
+      /** @var \Symfony\Component\Routing\Route $route */
+      // @todo: Are multiple methods possible here?
+      $methods = $route->getMethods();
+      // Only expose routes where the method is enabled in the configuration.
+      if ($methods && ($method = $methods[0]) && $rest_resource_config->hasSupportedFormats($method)) {
+        $route->setRequirement('_access_rest_csrf', 'TRUE');
+
+        // Check that authentication providers are defined.
+        if (empty($rest_resource_config->getSupportedAuthenticationProviders($method))) {
+          $this->logger->error('At least one authentication provider must be defined for resource @id', array(':id' => $rest_resource_config->id()));
+          continue;
+        }
+
+        // Check that formats are defined.
+        if (empty($rest_resource_config->getSupportedFormats($method))) {
+          $this->logger->error('At least one format must be defined for resource @id', array(':id' => $rest_resource_config->id()));
+          continue;
         }
+
+        // If the route has a format requirement, then verify that the
+        // resource has it.
+        $format_requirement = $route->getRequirement('_format');
+        if ($format_requirement && !$rest_resource_config->supportsFormat($method, $format_requirement)) {
+          continue;
+        }
+
+        // The configuration seems legit at this point, so we set the
+        // authentication provider and add the route.
+        $route->setOption('_auth', $rest_resource_config->getSupportedAuthenticationProviders($method));
+        $route->setDefault('_rest_resource_config', $rest_resource_config->id());
+        $collection->add("rest.$name", $route);
       }
+
     }
+    return $collection;
   }
 
 }
diff --git a/core/modules/rest/src/Tests/AuthTest.php b/core/modules/rest/src/Tests/AuthTest.php
index 08db9ab..e9fb7d7 100644
--- a/core/modules/rest/src/Tests/AuthTest.php
+++ b/core/modules/rest/src/Tests/AuthTest.php
@@ -16,7 +16,7 @@ class AuthTest extends RESTTestBase {
    *
    * @var array
    */
-  public static $modules = array('basic_auth', 'hal', 'rest', 'entity_test', 'comment');
+  public static $modules = array('basic_auth', 'hal', 'rest', 'entity_test');
 
   /**
    * Tests reading from an authenticated resource.
diff --git a/core/modules/rest/src/Tests/CreateTest.php b/core/modules/rest/src/Tests/CreateTest.php
index 035480b..28c8af6 100644
--- a/core/modules/rest/src/Tests/CreateTest.php
+++ b/core/modules/rest/src/Tests/CreateTest.php
@@ -23,7 +23,7 @@ class CreateTest extends RESTTestBase {
    *
    * @var array
    */
-  public static $modules = array('hal', 'rest', 'entity_test', 'comment');
+  public static $modules = array('hal', 'rest', 'entity_test', 'comment', 'node');
 
   /**
    * The 'serializer' service.
diff --git a/core/modules/rest/src/Tests/DeleteTest.php b/core/modules/rest/src/Tests/DeleteTest.php
index ccba38e..4cc8016 100644
--- a/core/modules/rest/src/Tests/DeleteTest.php
+++ b/core/modules/rest/src/Tests/DeleteTest.php
@@ -16,7 +16,7 @@ class DeleteTest extends RESTTestBase {
    *
    * @var array
    */
-  public static $modules = array('hal', 'rest', 'entity_test');
+  public static $modules = array('hal', 'rest', 'entity_test', 'node');
 
   /**
    * Tests several valid and invalid delete requests on all entity types.
diff --git a/core/modules/rest/src/Tests/NodeTest.php b/core/modules/rest/src/Tests/NodeTest.php
index 7f0ed81..9eedd2c 100644
--- a/core/modules/rest/src/Tests/NodeTest.php
+++ b/core/modules/rest/src/Tests/NodeTest.php
@@ -19,7 +19,7 @@ class NodeTest extends RESTTestBase {
    *
    * @var array
    */
-  public static $modules = array('hal', 'rest', 'comment');
+  public static $modules = array('hal', 'rest', 'comment', 'node');
 
   /**
    * Enables node specific REST API configuration and authentication.
diff --git a/core/modules/rest/src/Tests/PageCacheTest.php b/core/modules/rest/src/Tests/PageCacheTest.php
index 1958fdc..b29ab60 100644
--- a/core/modules/rest/src/Tests/PageCacheTest.php
+++ b/core/modules/rest/src/Tests/PageCacheTest.php
@@ -34,7 +34,7 @@ public function testConfigChangePageCache() {
     $this->httpRequest($entity->urlInfo()->setRouteParameter('_format', $this->defaultFormat), 'GET', NULL, $this->defaultMimeType);
     $this->assertResponse(200, 'HTTP response code is correct.');
     $this->assertHeader('x-drupal-cache', 'MISS');
-    $this->assertCacheTag('config:rest.settings');
+    $this->assertCacheTag('config:rest.resource.entity__entity_test');
     $this->assertCacheTag('entity_test:1');
     $this->assertCacheTag('entity_test_access:field_test_text');
 
@@ -42,17 +42,17 @@ public function testConfigChangePageCache() {
     $this->httpRequest($entity->urlInfo()->setRouteParameter('_format', $this->defaultFormat), 'GET', NULL, $this->defaultMimeType);
     $this->assertResponse(200, 'HTTP response code is correct.');
     $this->assertHeader('x-drupal-cache', 'HIT');
-    $this->assertCacheTag('config:rest.settings');
+    $this->assertCacheTag('config:rest.resource.entity__entity_test');
     $this->assertCacheTag('entity_test:1');
     $this->assertCacheTag('entity_test_access:field_test_text');
 
-    // Trigger a config save which should clear the page cache, so we should get
-    // a cache miss now for the same request.
-    $this->config('rest.settings')->save();
+    // Trigger an resource config save which should clear the page cache, so we
+    // should get a cache miss now for the same request.
+    $this->resourceConfigStorage->load('entity__entity_test')->save();
     $this->httpRequest($entity->urlInfo()->setRouteParameter('_format', $this->defaultFormat), 'GET', NULL, $this->defaultMimeType);
     $this->assertResponse(200, 'HTTP response code is correct.');
     $this->assertHeader('x-drupal-cache', 'MISS');
-    $this->assertCacheTag('config:rest.settings');
+    $this->assertCacheTag('config:rest.resource.entity__entity_test');
     $this->assertCacheTag('entity_test:1');
     $this->assertCacheTag('entity_test_access:field_test_text');
   }
diff --git a/core/modules/rest/src/Tests/RESTTestBase.php b/core/modules/rest/src/Tests/RESTTestBase.php
index 71b1a08..e4d3ed3 100644
--- a/core/modules/rest/src/Tests/RESTTestBase.php
+++ b/core/modules/rest/src/Tests/RESTTestBase.php
@@ -11,6 +11,13 @@
 abstract class RESTTestBase extends WebTestBase {
 
   /**
+   * The REST resource config storage.
+   *
+   * @var \Drupal\Core\Entity\EntityStorageInterface
+   */
+  protected $resourceConfigStorage;
+
+  /**
    * The default serialization format to use for testing REST operations.
    *
    * @var string
@@ -51,15 +58,18 @@
    *
    * @var array
    */
-  public static $modules = array('rest', 'entity_test', 'node');
+  public static $modules = array('rest', 'entity_test');
 
   protected function setUp() {
     parent::setUp();
     $this->defaultFormat = 'hal_json';
     $this->defaultMimeType = 'application/hal+json';
     $this->defaultAuth = array('cookie');
+    $this->resourceConfigStorage = $this->container->get('entity_type.manager')->getStorage('rest_resource_config');
     // Create a test content type for node testing.
-    $this->drupalCreateContentType(array('name' => 'resttest', 'type' => 'resttest'));
+    if (in_array('node', static::$modules)) {
+      $this->drupalCreateContentType(array('name' => 'resttest', 'type' => 'resttest'));
+    }
   }
 
   /**
@@ -255,24 +265,33 @@ protected function entityValues($entity_type) {
    * @param array $auth
    *   (Optional) The list of valid authentication methods.
    */
-  protected function enableService($resource_type, $method = 'GET', $format = NULL, $auth = NULL) {
-    // Enable REST API for this entity type.
-    $config = $this->config('rest.settings');
-    $settings = array();
-
+  protected function enableService($resource_type, $method = 'GET', $format = NULL, array $auth = []) {
     if ($resource_type) {
+      // Enable REST API for this entity type.
+      $resource_config_id = str_replace(':', '__', $resource_type);
+      // get entity by id
+      /** @var \Drupal\rest\RestResourceConfigInterface $resource_config */
+      $resource_config = $this->resourceConfigStorage->load($resource_config_id);
+      $resource_config = $resource_config ?: $this->resourceConfigStorage->create(['id' => $resource_config_id]);
+
       if ($format == NULL) {
         $format = $this->defaultFormat;
       }
-      $settings[$resource_type][$method]['supported_formats'][] = $format;
+      $resource_config->addSupportedFormat($method, $format);
 
-      if ($auth == NULL) {
+      if (!is_array($auth) || empty($auth)) {
         $auth = $this->defaultAuth;
       }
-      $settings[$resource_type][$method]['supported_auth'] = $auth;
+      foreach ($auth as $auth_provider) {
+        $resource_config->addSupportedAuthenticationProvider($method, $auth_provider);
+      }
+      $resource_config->save();
+    }
+    else {
+      foreach ($this->resourceConfigStorage->loadMultiple() as $resource_config) {
+        $resource_config->delete();
+      }
     }
-    $config->set('resources', $settings);
-    $config->save();
     $this->rebuildCache();
   }
 
diff --git a/core/modules/rest/src/Tests/ReadTest.php b/core/modules/rest/src/Tests/ReadTest.php
index 31b5db8..4ee05cd 100644
--- a/core/modules/rest/src/Tests/ReadTest.php
+++ b/core/modules/rest/src/Tests/ReadTest.php
@@ -17,7 +17,7 @@ class ReadTest extends RESTTestBase {
    *
    * @var array
    */
-  public static $modules = array('hal', 'rest', 'entity_test');
+  public static $modules = array('hal', 'rest', 'entity_test', 'node');
 
   /**
    * Tests several valid and invalid read requests on all entity types.
diff --git a/core/modules/rest/src/Tests/ResourceTest.php b/core/modules/rest/src/Tests/ResourceTest.php
index df99cc6..a171d7f 100644
--- a/core/modules/rest/src/Tests/ResourceTest.php
+++ b/core/modules/rest/src/Tests/ResourceTest.php
@@ -2,7 +2,6 @@
 
 namespace Drupal\rest\Tests;
 
-use Drupal\Component\Plugin\Exception\PluginNotFoundException;
 use Drupal\Core\Session\AccountInterface;
 use Drupal\user\Entity\Role;
 
@@ -32,9 +31,7 @@ class ResourceTest extends RESTTestBase {
    */
   protected function setUp() {
     parent::setUp();
-    $this->config = $this->config('rest.settings');
-
-    // Create an entity programmatically.
+    // Create an entity programmatic.
     $this->entity = $this->entityCreate('entity_test');
     $this->entity->save();
 
@@ -47,19 +44,12 @@ protected function setUp() {
    * Tests that a resource without formats cannot be enabled.
    */
   public function testFormats() {
-    $settings = array(
-      'entity:entity_test' => array(
-        'GET' => array(
-          'supported_auth' => array(
-            'basic_auth',
-          ),
-        ),
-      ),
-    );
-
+    /** @var \Drupal\rest\RestResourceConfigInterface $resource_config */
+    $resource_config = $this->resourceConfigStorage->create(['id' => 'entity__entity_test']);
     // Attempt to enable the resource.
-    $this->config->set('resources', $settings);
-    $this->config->save();
+    $resource_config
+      ->addSupportedAuthenticationProvider('GET', 'basic_auth')
+      ->save();
     $this->rebuildCache();
 
     // Verify that accessing the resource returns 406.
@@ -77,19 +67,12 @@ public function testFormats() {
    * Tests that a resource without authentication cannot be enabled.
    */
   public function testAuthentication() {
-    $settings = array(
-      'entity:entity_test' => array(
-        'GET' => array(
-          'supported_formats' => array(
-            'hal_json',
-          ),
-        ),
-      ),
-    );
-
+    /** @var \Drupal\rest\RestResourceConfigInterface $resource_config */
+    $resource_config = $this->resourceConfigStorage->create(['id' => 'entity__entity_test']);
     // Attempt to enable the resource.
-    $this->config->set('resources', $settings);
-    $this->config->save();
+    $resource_config
+      ->addSupportedFormat('GET', 'hal_json')
+      ->save();
     $this->rebuildCache();
 
     // Verify that accessing the resource returns 401.
@@ -118,30 +101,4 @@ public function testUriPaths() {
     }
   }
 
-  /**
-   * Tests that a resource with a missing plugin does not cause an exception.
-   */
-  public function testMissingPlugin() {
-    $settings = array(
-      'entity:nonexisting' => array(
-        'GET' => array(
-          'supported_formats' => array(
-            'hal_json',
-          ),
-        ),
-      ),
-    );
-
-    try {
-      // Attempt to enable the resource.
-      $this->config->set('resources', $settings);
-      $this->config->save();
-      $this->rebuildCache();
-      $this->pass('rest.settings referencing a missing REST resource plugin does not cause an exception.');
-    }
-    catch (PluginNotFoundException $e) {
-      $this->fail('rest.settings referencing a missing REST resource plugin caused an exception.');
-    }
-  }
-
 }
diff --git a/core/modules/rest/tests/src/Kernel/RequestHandlerTest.php b/core/modules/rest/tests/src/Kernel/RequestHandlerTest.php
index 36a482c..e09b175 100644
--- a/core/modules/rest/tests/src/Kernel/RequestHandlerTest.php
+++ b/core/modules/rest/tests/src/Kernel/RequestHandlerTest.php
@@ -1,18 +1,14 @@
 <?php
 
-/**
- * @file
- * Contains \Drupal\Tests\rest\Kernel\RequestHandlerTest.
- */
-
 namespace Drupal\Tests\rest\Kernel;
 
+use Drupal\Core\Entity\EntityStorageInterface;
 use Drupal\Core\Routing\RouteMatch;
 use Drupal\KernelTests\KernelTestBase;
 use Drupal\rest\Plugin\ResourceBase;
-use Drupal\rest\Plugin\Type\ResourcePluginManager;
 use Drupal\rest\RequestHandler;
 use Drupal\rest\ResourceResponse;
+use Drupal\rest\RestResourceConfigInterface;
 use Symfony\Component\HttpFoundation\Request;
 use Symfony\Component\Routing\Route;
 
@@ -32,11 +28,19 @@ class RequestHandlerTest extends KernelTestBase {
   public static $modules = ['serialization', 'rest'];
 
   /**
+   * The entity storage.
+   *
+   * @var \Prophecy\Prophecy\ObjectProphecy
+   */
+  protected $entityStorage;
+
+  /**
    * {@inheritdoc}
    */
   public function setUp() {
     parent::setUp();
-    $this->requestHandler = new RequestHandler();
+    $this->entityStorage = $this->prophesize(EntityStorageInterface::class);
+    $this->requestHandler = new RequestHandler($this->entityStorage->reveal());
     $this->requestHandler->setContainer($this->container);
   }
 
@@ -47,17 +51,19 @@ public function setUp() {
    */
   public function testBaseHandler() {
     $request = new Request();
-    $route_match = new RouteMatch('test', new Route('/rest/test', ['_plugin' => 'restplugin', '_format' => 'json']));
+    $route_match = new RouteMatch('test', new Route('/rest/test', ['_rest_resource_config' => 'restplugin', '_format' => 'json']));
 
     $resource = $this->prophesize(StubRequestHandlerResourcePlugin::class);
     $resource->get(NULL, $request)
       ->shouldBeCalled();
 
-    // Setup stub plugin manager that will return our plugin.
-    $stub = $this->prophesize(ResourcePluginManager::class);
-    $stub->createInstance('restplugin')
-      ->willReturn($resource->reveal());
-    $this->container->set('plugin.manager.rest', $stub->reveal());
+    // Setup the configuration.
+    $config = $this->prophesize(RestResourceConfigInterface::class);
+    $config->getResourcePlugin()->willReturn($resource->reveal());
+    $config->getCacheContexts()->willReturn([]);
+    $config->getCacheTags()->willReturn([]);
+    $config->getCacheMaxAge()->willReturn(12);
+    $this->entityStorage->load('restplugin')->willReturn($config->reveal());
 
     // Response returns NULL this time because response from plugin is not
     // a ResourceResponse so it is passed through directly.
@@ -89,15 +95,17 @@ public function testBaseHandler() {
    */
   public function testSerialization($data) {
     $request = new Request();
-    $route_match = new RouteMatch('test', new Route('/rest/test', ['_plugin' => 'restplugin', '_format' => 'json']));
+    $route_match = new RouteMatch('test', new Route('/rest/test', ['_rest_resource_config' => 'restplugin', '_format' => 'json']));
 
     $resource = $this->prophesize(StubRequestHandlerResourcePlugin::class);
 
-    // Setup stub plugin manager that will return our plugin.
-    $stub = $this->prophesize(ResourcePluginManager::class);
-    $stub->createInstance('restplugin')
-      ->willReturn($resource->reveal());
-    $this->container->set('plugin.manager.rest', $stub->reveal());
+    // Setup the configuration.
+    $config = $this->prophesize(RestResourceConfigInterface::class);
+    $config->getResourcePlugin()->willReturn($resource->reveal());
+    $config->getCacheContexts()->willReturn([]);
+    $config->getCacheTags()->willReturn([]);
+    $config->getCacheMaxAge()->willReturn(12);
+    $this->entityStorage->load('restplugin')->willReturn($config->reveal());
 
     $response = new ResourceResponse($data);
     $resource->get(NULL, $request)
diff --git a/core/modules/system/src/Tests/System/ResponseGeneratorTest.php b/core/modules/system/src/Tests/System/ResponseGeneratorTest.php
index 9d6cf4f..d0d22a2 100644
--- a/core/modules/system/src/Tests/System/ResponseGeneratorTest.php
+++ b/core/modules/system/src/Tests/System/ResponseGeneratorTest.php
@@ -16,7 +16,7 @@ class ResponseGeneratorTest extends RESTTestBase {
    *
    * @var array
    */
-  public static $modules = array('hal', 'rest', 'node');
+  public static $modules = array('hal', 'rest', 'node', 'basic_auth');
 
   /**
    * {@inheritdoc}
diff --git a/core/modules/system/src/Tests/Update/UpdatePathTestBase.php b/core/modules/system/src/Tests/Update/UpdatePathTestBase.php
index 19e1fcf..82169ad 100644
--- a/core/modules/system/src/Tests/Update/UpdatePathTestBase.php
+++ b/core/modules/system/src/Tests/Update/UpdatePathTestBase.php
@@ -265,7 +265,15 @@ protected function runUpdates() {
     }
 
     // Ensure that the update hooks updated all entity schema.
-    $this->assertFalse(\Drupal::service('entity.definition_update_manager')->needsUpdates(), 'After all updates ran, entity schema is up to date.');
+    $needs_updates = \Drupal::entityDefinitionUpdateManager()->needsUpdates();
+    $this->assertFalse($needs_updates, 'After all updates ran, entity schema is up to date.');
+    if ($needs_updates) {
+      foreach (\Drupal::entityDefinitionUpdateManager()->getChangeSummary() as $entity_type_id => $summary) {
+        foreach ($summary as $message) {
+          $this->fail($message);
+        }
+      }
+    }
   }
 
   /**
diff --git a/core/modules/system/system.install b/core/modules/system/system.install
index cdaeba6..ba1172e 100644
--- a/core/modules/system/system.install
+++ b/core/modules/system/system.install
@@ -1131,7 +1131,11 @@ function system_update_8004() {
   $manager = \Drupal::entityDefinitionUpdateManager();
   foreach (array_keys(\Drupal::entityManager()
     ->getDefinitions()) as $entity_type_id) {
-    $manager->updateEntityType($manager->getEntityType($entity_type_id));
+    // Only update the entity type if it already exists. This condition is
+    // needed in case new entity types are introduced after this update.
+    if ($entity_type = $manager->getEntityType($entity_type_id)) {
+      $manager->updateEntityType($entity_type);
+    }
   }
 }
 
