 config/install/jsonapi.resource_info.yml           |   1 -
 config/schema/jsonapi.schema.yml                   |   3 -
 jsonapi.services.yml                               |  20 ++-
 ...JsonApiResource.php => JsonApiResourceType.php} |  41 +++--
 src/Configuration/ResourceConfig.php               | 196 ---------------------
 src/Configuration/ResourceConfigInterface.php      | 127 -------------
 src/Configuration/ResourceManagerInterface.php     |  56 ------
 src/Context/CurrentContext.php                     |  25 ++-
 src/Context/CurrentContextInterface.php            |   4 +-
 src/EntityCollection.php                           |   4 +-
 src/EntityCollectionInterface.php                  |   5 +-
 src/LinkManager/LinkManager.php                    |  10 +-
 src/LinkManager/LinkManagerInterface.php           |   2 +-
 src/Normalizer/DocumentRootNormalizer.php          |   7 +-
 src/Normalizer/EntityNormalizer.php                |  18 +-
 src/Normalizer/EntityReferenceFieldNormalizer.php  |  15 +-
 src/Normalizer/RelationshipItemNormalizer.php      |  15 +-
 src/Normalizer/RelationshipNormalizer.php          |  24 +--
 src/Normalizer/Value/EntityNormalizerValue.php     |   5 +-
 .../Value/RelationshipItemNormalizerValue.php      |   2 +-
 .../Deriver/EntityDeriver.php}                     | 152 +++++++---------
 src/Plugin/Deriver/ResourceDeriver.php             |  82 ---------
 src/Plugin/JsonApiResourceInterface.php            |  14 --
 .../JsonApiResourceTypeInterface.php}              |  83 +++++----
 ...eManager.php => JsonApiResourceTypeManager.php} |  49 ++++--
 src/Plugin/jsonapi/BundleJsonApiResource.php       |  24 ---
 .../resource_type/EntityJsonApiResourceType.php}   | 118 ++++++-------
 src/Relationship.php                               |  14 +-
 src/RelationshipItem.php                           |  21 +--
 src/RelationshipItemInterface.php                  |   8 -
 src/RequestHandler.php                             |  19 +-
 src/Routing/Routes.php                             | 118 ++++++-------
 .../Kernel/Configuration/ResourceManagerTest.php   |   2 +-
 tests/src/Unit/Routing/RoutesTest.php              |   2 +-
 34 files changed, 379 insertions(+), 907 deletions(-)

diff --git a/config/install/jsonapi.resource_info.yml b/config/install/jsonapi.resource_info.yml
index b17ff5a..54fbb44 100644
--- a/config/install/jsonapi.resource_info.yml
+++ b/config/install/jsonapi.resource_info.yml
@@ -1,2 +1 @@
-prefix: api
 id_field: uuid
diff --git a/config/schema/jsonapi.schema.yml b/config/schema/jsonapi.schema.yml
index e7ddc88..3238540 100644
--- a/config/schema/jsonapi.schema.yml
+++ b/config/schema/jsonapi.schema.yml
@@ -1,9 +1,6 @@
 jsonapi.resource_info:
   type: config_object
   mapping:
-    prefix:
-      type: string
-      label: 'Prefix'
     id_field:
       type: string
       label: 'API field'
diff --git a/jsonapi.services.yml b/jsonapi.services.yml
index 99f5075..270dcbd 100644
--- a/jsonapi.services.yml
+++ b/jsonapi.services.yml
@@ -1,7 +1,8 @@
 services:
+  # Serialization.
   serializer.normalizer.entity_reference_item.jsonapi:
     class: Drupal\jsonapi\Normalizer\RelationshipItemNormalizer
-    arguments: ['@jsonapi.resource.manager', '@serializer.normalizer.document_root.jsonapi',]
+    arguments: ['@plugin.manager.jsonapi.resource_type', '@serializer.normalizer.document_root.jsonapi']
     tags:
       - { name: normalizer, priority: 21 }
   serializer.normalizer.field_item.jsonapi:
@@ -18,12 +19,12 @@ services:
       - { name: normalizer, priority: 21 }
   serializer.normalizer.entity_reference_field.jsonapi:
     class: Drupal\jsonapi\Normalizer\EntityReferenceFieldNormalizer
-    arguments: ['@jsonapi.link_manager', '@entity_field.manager', '@plugin.manager.field.field_type', '@jsonapi.resource.manager']
+    arguments: ['@jsonapi.link_manager', '@entity_field.manager', '@plugin.manager.field.field_type']
     tags:
       - { name: normalizer, priority: 31 }
   serializer.normalizer.relationship.jsonapi:
     class: Drupal\jsonapi\Normalizer\RelationshipNormalizer
-    arguments: ['@jsonapi.resource.manager', '@serializer.normalizer.document_root.jsonapi', '@jsonapi.link_manager']
+    arguments: ['@plugin.manager.jsonapi.resource_type', '@serializer.normalizer.document_root.jsonapi', '@jsonapi.link_manager']
     tags:
       - { name: normalizer, priority: 21 }
   serializer.normalizer.entity.jsonapi:
@@ -50,9 +51,8 @@ services:
     class: Drupal\jsonapi\Encoder\JsonEncoder
     tags:
       - { name: encoder, priority: 21, format: 'api_json' }
-  jsonapi.resource.manager:
-    class: Drupal\jsonapi\Configuration\ResourceManager
-    arguments: ['@entity_type.manager', '@entity_type.bundle.info', '@config.factory', '@module_handler']
+
+  # Routing.
   jsonapi.route_enhancer:
     class: Drupal\jsonapi\Routing\RouteEnhancer
     tags:
@@ -62,6 +62,8 @@ services:
     arguments: ['@entity_field.manager']
     tags:
       - { name: route_enhancer }
+
+  # Other.
   jsonapi.query_builder:
     class: Drupal\jsonapi\Query\QueryBuilder
     arguments: ['@entity_type.manager', '@jsonapi.current_context', '@jsonapi.field_resolver']
@@ -70,7 +72,7 @@ services:
     arguments: ['@router.no_access_checks', '@url_generator']
   jsonapi.current_context:
     class: Drupal\jsonapi\Context\CurrentContext
-    arguments: ['@jsonapi.resource.manager', '@request_stack']
+    arguments: ['@plugin.manager.jsonapi.resource_type', '@request_stack']
   jsonapi.field_resolver:
     class: Drupal\jsonapi\Context\FieldResolver
     arguments: ['@jsonapi.current_context', '@entity_field.manager']
@@ -85,8 +87,8 @@ services:
     arguments: ['@entity.manager']
   jsonapi.error_handler:
     class: Drupal\jsonapi\Error\ErrorHandler
-  plugin.manager.resource.processor:
-    class: Drupal\jsonapi\Plugin\JsonApiResourceManager
+  plugin.manager.jsonapi.resource_type:
+    class: Drupal\jsonapi\Plugin\JsonApiResourceTypeManager
     parent: default_plugin_manager
   jsonapi.exception_subscriber:
     class: Drupal\jsonapi\EventSubscriber\DefaultExceptionSubscriber
diff --git a/src/Annotation/JsonApiResource.php b/src/Annotation/JsonApiResourceType.php
similarity index 29%
rename from src/Annotation/JsonApiResource.php
rename to src/Annotation/JsonApiResourceType.php
index 277de71..1df51ad 100644
--- a/src/Annotation/JsonApiResource.php
+++ b/src/Annotation/JsonApiResourceType.php
@@ -5,14 +5,19 @@ namespace Drupal\jsonapi\Annotation;
 use Drupal\Component\Annotation\Plugin;
 
 /**
- * Defines a JSON API Resource item annotation object.
+ * Defines a JSON API resource 'type' annotation object.
  *
- * @see \Drupal\jsonapi\Plugin\JsonApiResourceManager
+ * Plugin Namespace: Plugin\jsonapi\resource_type
+ *
+ * @see \Drupal\jsonapi\Plugin\JsonApiResourceTypeManager
+ * @see \Drupal\jsonapi\Plugin\JsonApiResourceTypeInterface
  * @see plugin_api
  *
+ * @see http://jsonapi.org/format/#document-resource-identifier-objects — 'type'
+ *
  * @Annotation
  */
-class JsonApiResource extends Plugin {
+class JsonApiResourceType extends Plugin {
 
   /**
    * The plugin ID.
@@ -31,31 +36,37 @@ class JsonApiResource extends Plugin {
   public $label;
 
   /**
-   * The entity type ID.
+   * The type hierarchy (for hierarchical types).
    *
-   * @var string
+   * The first level is required. Secondary and further levels are optional. A
+   * JSON API type is generated from this automatically: 'level1--level2'.
+   *
+   * @var string[]
    */
-  public $entityType;
+  public $type_hierarchy;
 
   /**
-   * The bundle ID.
+   * The serialization class to deserialize serialized data into.
    *
-   * @var string
+   * @var string (optional)
    */
-  public $bundle;
+  public $serialization_class;
 
   /**
-   * Information about the data resources.
+   * The requirements to add to every JSON API route for this resource type.
+   *
+   * @see \Symfony\Component\Routing\Route
    *
    * @var array
    */
-  public $data;
+  public $route_requirements;
 
   /**
-   * TRUE if the plugin is enabled.
+   * The options to add to every JSON API route for this resource type.
+   *
+   * @see \Symfony\Component\Routing\Route
    *
-   * @var bool
+   * @var array
    */
-  public $enabled;
-
+  public $route_options;
 }
diff --git a/src/Configuration/ResourceConfig.php b/src/Configuration/ResourceConfig.php
deleted file mode 100644
index d3b9f55..0000000
--- a/src/Configuration/ResourceConfig.php
+++ /dev/null
@@ -1,196 +0,0 @@
-<?php
-
-namespace Drupal\jsonapi\Configuration;
-
-use Drupal\Core\Config\ConfigFactoryInterface;
-use Drupal\Core\Entity\EntityTypeManagerInterface;
-
-/**
- * Class ResourceConfig.
- *
- * This object contains all the information needed to generate all the routes
- * associated with a JSON API type. In the future this is going to be
- * constructed (maybe?) from a configuration entity.
- *
- * @package Drupal\jsonapi\Configuration
- */
-class ResourceConfig implements ResourceConfigInterface {
-
-  /**
-   * Holds the configuration that is global to all the JSON API types.
-   *
-   * @var object
-   */
-  protected $globalConfig;
-
-  /**
-   * Holds the entity type manager.
-   *
-   * @var EntityTypeManagerInterface
-   */
-  protected $entityTypeManager;
-
-  /**
-   * The entity type ID.
-   *
-   * @var string
-   */
-  protected $entityTypeId;
-
-  /**
-   * The bundle ID.
-   *
-   * @var string
-   */
-  protected $bundleId;
-
-  /**
-   * The type name.
-   *
-   * @var string
-   */
-  protected $typeName;
-
-  /**
-   * The base resource path.
-   *
-   * @var string
-   */
-  protected $path;
-
-  /**
-   * The class to which a payload converts to.
-   *
-   * @var string
-   */
-  protected $deserializationTargetClass;
-
-  /**
-   * Is enabled?
-   *
-   * @var bool
-   */
-  protected $isEnabled = TRUE;
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getGlobalConfig() {
-    return $this->globalConfig;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getEntityTypeId() {
-    return $this->entityTypeId;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function setEntityTypeId($entity_type_id) {
-    $this->entityTypeId = $entity_type_id;
-    $this->deserializationTargetClass = $this->entityTypeManager
-      ->getDefinition($entity_type_id)
-      ->getClass();
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getTypeName() {
-    return $this->typeName;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function setTypeName($type_name) {
-    $this->typeName = $type_name;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getPath() {
-    return $this->path;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function setPath($path) {
-    $this->path = $path;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getBundleId() {
-    return $this->bundleId;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function setBundleId($bundle_id) {
-    $this->bundleId = $bundle_id;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getStorage() {
-    return $this->entityTypeManager->getStorage($this->entityTypeId);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getDeserializationTargetClass() {
-    return $this->deserializationTargetClass;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getIdKey() {
-    return $this->getGlobalConfig()->get('id_field');
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function isEnabled() {
-    return $this->isEnabled;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function enable() {
-    $this->isEnabled = TRUE;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function disable() {
-    $this->isEnabled = FALSE;
-  }
-
-  /**
-   * Instantiates a ResourceConfig object.
-   *
-   * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
-   *   The configuration factory.
-   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
-   *   The entity type manager.
-   */
-  public function __construct(ConfigFactoryInterface $config_factory, EntityTypeManagerInterface $entity_type_manager) {
-    $this->globalConfig = $config_factory->get('jsonapi.resource_info');
-    $this->entityTypeManager = $entity_type_manager;
-  }
-
-}
diff --git a/src/Configuration/ResourceConfigInterface.php b/src/Configuration/ResourceConfigInterface.php
deleted file mode 100644
index 95af84c..0000000
--- a/src/Configuration/ResourceConfigInterface.php
+++ /dev/null
@@ -1,127 +0,0 @@
-<?php
-
-
-namespace Drupal\jsonapi\Configuration;
-
-/**
- * Class ResourceConfigInterface.
- *
- * @package Drupal\jsonapi\Configuration
- */
-interface ResourceConfigInterface {
-
-  /**
-   * Gets the entity type id.
-   *
-   * @return string
-   *   The entity type id.
-   */
-  public function getEntityTypeId();
-
-  /**
-   * Sets the entity type id.
-   *
-   * @param string $entity_type_id
-   *   The entityTypeId to set.
-   */
-  public function setEntityTypeId($entity_type_id);
-
-  /**
-   * Gets the type name.
-   *
-   * @return string
-   *   The type name.
-   */
-  public function getTypeName();
-
-  /**
-   * Sets the type name.
-   *
-   * @param string $type_name
-   *   The type name to set.
-   */
-  public function setTypeName($type_name);
-
-  /**
-   * Gets the path.
-   *
-   * @return string
-   *   The path.
-   */
-  public function getPath();
-
-  /**
-   * Sets the path.
-   *
-   * @param string $path
-   *   The path to set.
-   */
-  public function setPath($path);
-
-  /**
-   * Gets the bundle ID.
-   *
-   * @return string
-   *   The bundleId.
-   */
-  public function getBundleId();
-
-  /**
-   * Sets the bundle ID.
-   *
-   * @param string $bundle_id
-   *   The bundleId to set.
-   */
-  public function setBundleId($bundle_id);
-
-  /**
-   * Gets the global configuration.
-   *
-   * @return \Drupal\Core\Config\Config
-   *   The global configuration.
-   */
-  public function getGlobalConfig();
-
-  /**
-   * Gets the underlying entity storage for the resource.
-   *
-   * @return \Drupal\Core\Entity\EntityStorageInterface
-   *   The appropriate entity storage interface.
-   */
-  public function getStorage();
-
-  /**
-   * Gets the deserialization target class.
-   *
-   * @return string
-   *   The deserialization target class.
-   */
-  public function getDeserializationTargetClass();
-
-  /**
-   * Get the entity key used for the ID.
-   *
-   * @return string
-   *   The key.
-   */
-  public function getIdKey();
-
-  /**
-   * Is the resource enabled?
-   *
-   * @return bool
-   *   TRUE if the resource is enabled. FALSE otherwise.
-   */
-  public function isEnabled();
-
-  /**
-   * Enable the resource.
-   */
-  public function enable();
-
-  /**
-   * Disable the resource.
-   */
-  public function disable();
-
-}
diff --git a/src/Configuration/ResourceManagerInterface.php b/src/Configuration/ResourceManagerInterface.php
deleted file mode 100644
index 74d1737..0000000
--- a/src/Configuration/ResourceManagerInterface.php
+++ /dev/null
@@ -1,56 +0,0 @@
-<?php
-
-
-namespace Drupal\jsonapi\Configuration;
-
-/**
- * Class ResourceManagerInterface.
- *
- * @package Drupal\jsonapi
- */
-interface ResourceManagerInterface {
-
-  /**
-   * Get all the resource configuration objects.
-   *
-   * @param bool $include_disabled
-   *   TRUE to return disabled resources as well.
-   *
-   * @return ResourceConfigInterface[]
-   *   The list of resource configs representing JSON API types.
-   */
-  public function all($include_disabled = FALSE);
-
-  /**
-   * Finds a resource config.
-   *
-   * @param string $entity_type_id
-   *   The entity type id.
-   * @param string $bundle_id
-   *   The id for the bundle to find.
-   *
-   * @return ResourceConfigInterface
-   *   The resource config found. NULL if none was found.
-   */
-  public function get($entity_type_id, $bundle_id);
-
-  /**
-   * Get the entity type manager.
-   *
-   * @return \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
-   *   The entity type manager.
-   */
-  public function getEntityTypeManager();
-
-  /**
-   * Entity type has a bundle.
-   *
-   * @param string $entity_type_id
-   *   The entity type ID.
-   *
-   * @return bool
-   *   TRUE if the provided entity type has a bundle.
-   */
-  public function hasBundle($entity_type_id);
-
-}
diff --git a/src/Context/CurrentContext.php b/src/Context/CurrentContext.php
index 48e2c7e..ddbdf17 100644
--- a/src/Context/CurrentContext.php
+++ b/src/Context/CurrentContext.php
@@ -3,6 +3,7 @@
 namespace Drupal\jsonapi\Context;
 
 use Drupal\jsonapi\Configuration\ResourceManagerInterface;
+use Drupal\jsonapi\Plugin\JsonApiResourceTypeManager;
 use Symfony\Cmf\Component\Routing\RouteObjectInterface;
 use Symfony\Component\HttpFoundation\RequestStack;
 use Symfony\Component\HttpFoundation\Request;
@@ -25,11 +26,11 @@ class CurrentContext implements CurrentContextInterface {
   protected $currentRoute;
 
   /**
-   * The resource manager.
+   * JSON API Resource Type plugin manager.
    *
-   * @var \Drupal\jsonapi\Configuration\ResourceManagerInterface
+   * @var \Drupal\jsonapi\Plugin\JsonApiResourceTypeManager
    */
-  protected $resourceManager;
+  protected $jsonApiResourceTypeManager;
 
   /**
    * The current resource config.
@@ -48,13 +49,11 @@ class CurrentContext implements CurrentContextInterface {
   /**
    * Creates a CurrentContext object.
    *
-   * @param \Drupal\jsonapi\Configuration\ResourceManagerInterface $resource_manager
-   *   The resource manager service.
    * @param \Symfony\Component\HttpFoundation\RequestStack $request_stack
    *   The request stack.
    */
-  public function __construct(ResourceManagerInterface $resource_manager, RequestStack $request_stack) {
-    $this->resourceManager = $resource_manager;
+  public function __construct(JsonApiResourceTypeManager $jsonapi_resource_type_manager, RequestStack $request_stack) {
+    $this->jsonApiResourceTypeManager = $jsonapi_resource_type_manager;
     $this->currentRequest = $request_stack->getCurrentRequest();
     if ($route = $this->currentRequest->get(RouteObjectInterface::ROUTE_OBJECT)) {
       $this->setCurrentRoute($route);
@@ -70,13 +69,13 @@ class CurrentContext implements CurrentContextInterface {
 
   /**
    * {@inheritdoc}
+   *
+   * todo rename
    */
   public function getResourceConfig() {
     if (!isset($this->resourceConfig)) {
-      $entity_type_id = $this->getCurrentRoute()->getRequirement('_entity_type');
-      $bundle_id = $this->getCurrentRoute()->getRequirement('_bundle');
-      $this->resourceConfig = $this->resourceManager
-        ->get($entity_type_id, $bundle_id);
+      $plugin_id = $this->getCurrentRoute()->getOption('_jsonapi_plugin_id');
+      $this->resourceConfig = $this->jsonApiResourceTypeManager->createInstance($plugin_id);
     }
 
     return $this->resourceConfig;
@@ -99,8 +98,8 @@ class CurrentContext implements CurrentContextInterface {
   /**
    * {@inheritdoc}
    */
-  public function getResourceManager() {
-    return $this->resourceManager;
+  public function getJsonApiResourceTypeManager() {
+    return $this->jsonApiResourceTypeManager;
   }
 
   /**
diff --git a/src/Context/CurrentContextInterface.php b/src/Context/CurrentContextInterface.php
index fda80a1..122959f 100644
--- a/src/Context/CurrentContextInterface.php
+++ b/src/Context/CurrentContextInterface.php
@@ -43,9 +43,9 @@ interface CurrentContextInterface {
   /**
    * Returns the resource manager.
    *
-   * @return \Drupal\jsonapi\Configuration\ResourceManagerInterface
+   * @return \Drupal\jsonapi\Plugin\JsonApiResourceTypeManager
    */
-  public function getResourceManager();
+  public function getJsonApiResourceTypeManager();
 
   /**
    * Get a value by key from the _json_api_params route parameter.
diff --git a/src/EntityCollection.php b/src/EntityCollection.php
index 88223fa..917a300 100644
--- a/src/EntityCollection.php
+++ b/src/EntityCollection.php
@@ -3,9 +3,7 @@
 namespace Drupal\jsonapi;
 
 /**
- * Class EntityCollection.
- *
- * @package Drupal\jsonapi
+ * @internal
  */
 class EntityCollection implements EntityCollectionInterface {
 
diff --git a/src/EntityCollectionInterface.php b/src/EntityCollectionInterface.php
index 2069cc7..d7b1a8f 100644
--- a/src/EntityCollectionInterface.php
+++ b/src/EntityCollectionInterface.php
@@ -4,9 +4,8 @@
 namespace Drupal\jsonapi;
 
 /**
- * Class EntityCollectionInterface.
- *
- * @package Drupal\jsonapi
+ * @internal
+ * @todo Make this non-entity specific.
  */
 interface EntityCollectionInterface extends \IteratorAggregate, \Countable {
 
diff --git a/src/LinkManager/LinkManager.php b/src/LinkManager/LinkManager.php
index 3d79bf8..318f59f 100644
--- a/src/LinkManager/LinkManager.php
+++ b/src/LinkManager/LinkManager.php
@@ -43,14 +43,14 @@ class LinkManager implements LinkManagerInterface {
   /**
    * {@inheritdoc}
    */
-  public function getEntityLink($entity_id, ResourceConfigInterface $resource_config, array $route_parameters, $key) {
+  public function getEntityLink($entity_id, $jsonapi_resource_type_plugin_definition, array $route_parameters, $key) {
+    $type_hierarchy = $jsonapi_resource_type_plugin_definition['type_hierarchy'];
     $route_parameters += [
-      $resource_config->getEntityTypeId() => $entity_id,
+      $type_hierarchy[0] => $entity_id,
       '_format' => 'api_json',
     ];
-    $prefix = $resource_config->getGlobalConfig()->get('prefix');
-    $route_key = sprintf('%s.dynamic.%s.%s', $prefix, $resource_config->getTypeName(), $key);
-    return $this->urlGenerator->generateFromRoute($route_key, $route_parameters, ['absolute' => TRUE]);
+    $route_name = 'jsonapi.' . implode('.', $type_hierarchy) . '.individual';
+    return $this->urlGenerator->generateFromRoute($route_name, $route_parameters, ['absolute' => TRUE]);
   }
 
   /**
diff --git a/src/LinkManager/LinkManagerInterface.php b/src/LinkManager/LinkManagerInterface.php
index ec43d84..64845cf 100644
--- a/src/LinkManager/LinkManagerInterface.php
+++ b/src/LinkManager/LinkManagerInterface.php
@@ -29,7 +29,7 @@ interface LinkManagerInterface {
    * @return string
    *   The URL string.
    */
-  public function getEntityLink($entity_id, ResourceConfigInterface $resource_config, array $route_parameters, $key);
+  public function getEntityLink($entity_id, $resource_config, array $route_parameters, $key);
 
   /**
    * Get the full URL for a given request object.
diff --git a/src/Normalizer/DocumentRootNormalizer.php b/src/Normalizer/DocumentRootNormalizer.php
index 11f6603..7c3d9d4 100644
--- a/src/Normalizer/DocumentRootNormalizer.php
+++ b/src/Normalizer/DocumentRootNormalizer.php
@@ -75,7 +75,8 @@ class DocumentRootNormalizer extends NormalizerBase implements DenormalizerInter
         }
       }, $data['data']['relationships']);
 
-      $id_key = $this->currentContext->getResourceConfig()->getIdKey();
+      // @todo fix in https://www.drupal.org/node/2831134
+      $id_key = 'uuid';
 
       // Get an array of ids for every relationship.
       $relationships = array_map(function ($relationship) use ($id_key) {
@@ -84,8 +85,8 @@ class DocumentRootNormalizer extends NormalizerBase implements DenormalizerInter
           return $id_list;
         }
         list($entity_type_id,) = explode('--', $relationship['data'][0]['type']);
-        $entity_storage = $this->currentContext->getResourceManager()
-          ->getEntityTypeManager()
+        $entity_storage = \Drupal::getContainer()
+          ->get('entity_type.manager')
           ->getStorage($entity_type_id);
         // In order to maintain the order ($delta) of the relationships, we need
         // to load the entities and explore the $id_key value.
diff --git a/src/Normalizer/EntityNormalizer.php b/src/Normalizer/EntityNormalizer.php
index eefd8f7..b1780d4 100644
--- a/src/Normalizer/EntityNormalizer.php
+++ b/src/Normalizer/EntityNormalizer.php
@@ -41,13 +41,6 @@ class EntityNormalizer extends NormalizerBase implements DenormalizerInterface,
   protected $linkManager;
 
   /**
-   * The resource manager.
-   *
-   * @var \Drupal\jsonapi\Configuration\ResourceManagerInterface
-   */
-  protected $resourceManager;
-
-  /**
    * The current JSON API request context.
    *
    * @var \Drupal\jsonapi\Context\CurrentContextInterface
@@ -65,7 +58,6 @@ class EntityNormalizer extends NormalizerBase implements DenormalizerInterface,
   public function __construct(LinkManagerInterface $link_manager, CurrentContextInterface $current_context) {
     $this->linkManager = $link_manager;
     $this->currentContext = $current_context;
-    $this->resourceManager = $current_context->getResourceManager();
   }
 
   /**
@@ -73,14 +65,16 @@ class EntityNormalizer extends NormalizerBase implements DenormalizerInterface,
    */
   public function normalize($entity, $format = NULL, array $context = array()) {
     // If the fields to use were specified, only output those field values.
-    $context['resource_config'] = $this->resourceManager->get(
+    $context['resource_config'] = $this->currentContext->getJsonApiResourceTypeManager()->getDefinitionByTypeHierarchy(
       $entity->getEntityTypeId(),
-      $entity->bundle()
+      $entity->getEntityType()->getBundleEntityType() === NULL
+        ? NULL
+        : $entity->bundle()
     );
-    $resource_type = $context['resource_config']->getTypeName();
+    $resource_type = implode('--', $context['resource_config']['type_hierarchy']);
     // Get the bundle ID of the requested resource. This is used to determine if
     // this is a bundle level resource or an entity level resource.
-    $bundle_id = $context['resource_config']->getBundleId();
+    $bundle_id = $context['resource_config']->getTypeHierarchy;
     if (!empty($context['sparse_fieldset'][$resource_type])) {
       $field_names = $context['sparse_fieldset'][$resource_type];
     }
diff --git a/src/Normalizer/EntityReferenceFieldNormalizer.php b/src/Normalizer/EntityReferenceFieldNormalizer.php
index 855ac04..95b44e6 100644
--- a/src/Normalizer/EntityReferenceFieldNormalizer.php
+++ b/src/Normalizer/EntityReferenceFieldNormalizer.php
@@ -56,14 +56,11 @@ class EntityReferenceFieldNormalizer extends FieldNormalizer implements Denormal
    *   The entity field manager.
    * @param \Drupal\Core\Field\FieldTypePluginManagerInterface $plugin_manager
    *   The plugin manager for fields.
-   * @param \Drupal\jsonapi\Configuration\ResourceManagerInterface $resource_manager
-   *   The resource manager.
    */
-  public function __construct(LinkManagerInterface $link_manager, EntityFieldManagerInterface $field_manager, FieldTypePluginManagerInterface $plugin_manager, ResourceManagerInterface $resource_manager) {
+  public function __construct(LinkManagerInterface $link_manager, EntityFieldManagerInterface $field_manager, FieldTypePluginManagerInterface $plugin_manager) {
     $this->linkManager = $link_manager;
     $this->fieldManager = $field_manager;
     $this->pluginManager = $plugin_manager;
-    $this->resourceManager = $resource_manager;
   }
 
   /**
@@ -81,7 +78,7 @@ class EntityReferenceFieldNormalizer extends FieldNormalizer implements Denormal
     $entity_collection = new EntityCollection(array_map(function ($item) {
       return $item->get('entity')->getValue();
     }, (array) $field->getIterator()));
-    $relationship = new Relationship($this->resourceManager, $field->getName(), $cardinality, $entity_collection, $field->getEntity(), $main_property);
+    $relationship = new Relationship($field->getName(), $cardinality, $entity_collection, $field->getEntity(), $main_property);
     return $this->serializer->normalize($relationship, $format, $context);
   }
 
@@ -170,12 +167,10 @@ class EntityReferenceFieldNormalizer extends FieldNormalizer implements Denormal
    */
   protected function getAllowedResourceTypes(FieldItemDataDefinition $item_definition) {
     // Build the list of allowed resources.
-    $target_entity_id = $item_definition->getSetting('target_type');
+    $target_entity_type_id = $item_definition->getSetting('target_type');
     $handler_settings = $item_definition->getSetting('handler_settings');
-    return array_map(function ($target_bundle_id) use ($target_entity_id) {
-      return $this->resourceManager
-        ->get($target_entity_id, $target_bundle_id)
-        ->getTypeName();
+    return array_map(function ($target_bundle) use ($target_entity_type_id) {
+      return sprintf('%s--%s', $target_entity_type_id, $target_bundle);
     }, $handler_settings['target_bundles']);
   }
 
diff --git a/src/Normalizer/RelationshipItemNormalizer.php b/src/Normalizer/RelationshipItemNormalizer.php
index d1e32b1..2c7ad08 100644
--- a/src/Normalizer/RelationshipItemNormalizer.php
+++ b/src/Normalizer/RelationshipItemNormalizer.php
@@ -6,6 +6,7 @@ use Drupal\Core\Cache\RefinableCacheableDependencyInterface;
 use Drupal\Core\Cache\RefinableCacheableDependencyTrait;
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\jsonapi\Configuration\ResourceManagerInterface;
+use Drupal\jsonapi\Plugin\JsonApiResourceTypeManager;
 use Drupal\jsonapi\RelationshipItemInterface;
 use Drupal\serialization\EntityResolver\UuidReferenceInterface;
 
@@ -28,7 +29,7 @@ class RelationshipItemNormalizer extends FieldItemNormalizer implements UuidRefe
    *
    * @var \Drupal\jsonapi\Configuration\ResourceManagerInterface
    */
-  protected $resourceManager;
+  protected $jsonApiResourceTypeManager;
 
   /**
    * The document normalizer.
@@ -45,8 +46,8 @@ class RelationshipItemNormalizer extends FieldItemNormalizer implements UuidRefe
    * @param \Drupal\jsonapi\Normalizer\DocumentRootNormalizerInterface $document_root_normalizer
    *   The document root normalizer for the include.
    */
-  public function __construct(ResourceManagerInterface $resource_manager, DocumentRootNormalizerInterface $document_root_normalizer) {
-    $this->resourceManager = $resource_manager;
+  public function __construct(JsonApiResourceTypeManager $jsonapi_resource_type_manager, DocumentRootNormalizerInterface $document_root_normalizer) {
+    $this->jsonApiResourceTypeManager = $jsonapi_resource_type_manager;
     $this->documentRootNormalizer = $document_root_normalizer;
   }
 
@@ -102,8 +103,12 @@ class RelationshipItemNormalizer extends FieldItemNormalizer implements UuidRefe
    */
   protected function buildSubContext($context, EntityInterface $entity, $host_field_name) {
     // Swap out the context for the context of the referenced resource.
-    $context['resource_config'] = $this->resourceManager
-      ->get($entity->getEntityTypeId(), $entity->bundle());
+    $context['resource_config'] = $this->jsonApiResourceTypeManager->getDefinitionByTypeHierarchy(
+      $entity->getEntityTypeId(),
+      $entity->getEntityType()->getBundleEntityType() === NULL
+        ? NULL
+        : $entity->bundle()
+    );
     // Since we're going one level down the only includes we need are the ones
     // that apply to this level as well.
     $include_candidates = array_filter($context['include'], function ($include) use ($host_field_name) {
diff --git a/src/Normalizer/RelationshipNormalizer.php b/src/Normalizer/RelationshipNormalizer.php
index 41e8c7f..1a3b911 100644
--- a/src/Normalizer/RelationshipNormalizer.php
+++ b/src/Normalizer/RelationshipNormalizer.php
@@ -5,6 +5,7 @@ namespace Drupal\jsonapi\Normalizer;
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\jsonapi\Configuration\ResourceManagerInterface;
 use Drupal\jsonapi\LinkManager\LinkManagerInterface;
+use Drupal\jsonapi\Plugin\JsonApiResourceTypeManager;
 use Drupal\jsonapi\Relationship;
 use Symfony\Component\Serializer\Exception\UnexpectedValueException;
 
@@ -29,7 +30,7 @@ class RelationshipNormalizer extends NormalizerBase {
    *
    * @var \Drupal\jsonapi\Configuration\ResourceManagerInterface
    */
-  protected $resourceManager;
+  protected $jsonApiResourceTypeManager;
 
   /**
    * The link manager.
@@ -48,15 +49,13 @@ class RelationshipNormalizer extends NormalizerBase {
   /**
    * RelationshipNormalizer constructor.
    *
-   * @param \Drupal\jsonapi\Configuration\ResourceManagerInterface $resource_manager
-   *   The resource manager.
    * @param \Drupal\jsonapi\Normalizer\DocumentRootNormalizerInterface $document_root_normalizer
    *   The document root normalizer for the include.
    * @param \Drupal\jsonapi\LinkManager\LinkManagerInterface $link_manager
    *   The link manager.
    */
-  public function __construct(ResourceManagerInterface $resource_manager, DocumentRootNormalizerInterface $document_root_normalizer, LinkManagerInterface $link_manager) {
-    $this->resourceManager = $resource_manager;
+  public function __construct(JsonApiResourceTypeManager $jsonapi_resource_type_manager, DocumentRootNormalizerInterface $document_root_normalizer, LinkManagerInterface $link_manager) {
+    $this->jsonApiResourceTypeManager = $jsonapi_resource_type_manager;
     $this->documentRootNormalizer = $document_root_normalizer;
     $this->linkManager = $link_manager;
   }
@@ -85,15 +84,12 @@ class RelationshipNormalizer extends NormalizerBase {
     /* @var \Drupal\jsonapi\RelationshipInterface $relationship */
     $normalizer_items = array();
     foreach ($relationship->getItems() as $relationship_item) {
-      /* @var \Drupal\jsonapi\RelationshipItemInterface $relationship_item */
-      if (!$relationship_item->resourceIsEnabled()) {
-        continue;
-      }
       $normalizer_items[] = $this->serializer->normalize($relationship_item, $format, $context);
     }
     $cardinality = $relationship->getCardinality();
     $link_context = [
-      'host_entity_id' => $context['resource_config']->getIdKey() == 'uuid' ? $relationship->getHostEntity()->uuid() : $relationship->getHostEntity()->id(),
+      // @Todo
+      'host_entity_id' => $relationship->getHostEntity()->uuid(),
       'field_name' => $relationship->getPropertyName(),
       'link_manager' => $this->linkManager,
       'resource_config' => $context['resource_config'],
@@ -120,8 +116,12 @@ class RelationshipNormalizer extends NormalizerBase {
    */
   protected function buildSubContext($context, EntityInterface $entity, $host_field_name) {
     // Swap out the context for the context of the referenced resource.
-    $context['resource_config'] = $this->resourceManager
-      ->get($entity->getEntityTypeId(), $entity->bundle());
+    $context['resource_config'] = $this->jsonApiResourceTypeManager->getDefinitionByTypeHierarchy(
+      $entity->getEntityTypeId(),
+      $entity->getEntityType()->getBundleEntityType() === NULL
+        ? NULL
+        : $entity->bundle()
+    );
     // Since we're going one level down the only includes we need are the ones
     // that apply to this level as well.
     $include_candidates = array_filter($context['include'], function ($include) use ($host_field_name) {
diff --git a/src/Normalizer/Value/EntityNormalizerValue.php b/src/Normalizer/Value/EntityNormalizerValue.php
index 29bf5ec..12ee405 100644
--- a/src/Normalizer/Value/EntityNormalizerValue.php
+++ b/src/Normalizer/Value/EntityNormalizerValue.php
@@ -86,10 +86,11 @@ class EntityNormalizerValue implements EntityNormalizerValueInterface {
    * {@inheritdoc}
    */
   public function rasterizeValue() {
-    $id_key = $this->context['resource_config']->getIdKey();
+    // @todo
+    $id_key = 'uuid';
     // Create the array of normalized fields, starting with the URI.
     $rasterized = [
-      'type' => $this->context['resource_config']->getTypeName(),
+      'type' => implode('--', $this->context['resource_config']['type_hierarchy']),
       'id' => $id_key == 'uuid' ? $this->entity->uuid() : $this->entity->id(),
       'attributes' => [],
       'relationships' => [],
diff --git a/src/Normalizer/Value/RelationshipItemNormalizerValue.php b/src/Normalizer/Value/RelationshipItemNormalizerValue.php
index c00af71..03b5c40 100644
--- a/src/Normalizer/Value/RelationshipItemNormalizerValue.php
+++ b/src/Normalizer/Value/RelationshipItemNormalizerValue.php
@@ -40,7 +40,7 @@ class RelationshipItemNormalizerValue extends FieldItemNormalizerValue implement
       return $value;
     }
     return [
-      'type' => $this->resource->getTypeName(),
+      'type' => implode('--', $this->resource['type_hierarchy']),
       'id' => $value,
     ];
   }
diff --git a/src/Configuration/ResourceManager.php b/src/Plugin/Deriver/EntityDeriver.php
similarity index 22%
rename from src/Configuration/ResourceManager.php
rename to src/Plugin/Deriver/EntityDeriver.php
index 106efc1..552bc91 100644
--- a/src/Configuration/ResourceManager.php
+++ b/src/Plugin/Deriver/EntityDeriver.php
@@ -1,33 +1,34 @@
 <?php
 
-namespace Drupal\jsonapi\Configuration;
+namespace Drupal\jsonapi\Plugin\Deriver;
 
-use Drupal\Core\Config\ConfigFactoryInterface;
+use Drupal\Component\Plugin\Derivative\DeriverBase;
 use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
 use Drupal\Core\Entity\EntityTypeManagerInterface;
-use Drupal\Core\Extension\ModuleHandlerInterface;
-use Symfony\Component\HttpKernel\Exception\PreconditionFailedHttpException;
+use Drupal\Core\Plugin\Discovery\ContainerDeriverInterface;
+use Drupal\jsonapi\Configuration\ResourceManagerInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
- * Class ResourceManager.
+ * Provides a resource plugin definition for every entity type and bundle.
  *
- * @package Drupal\jsonapi
+ * @see \Drupal\jsonapi\Plugin\jsonapi\resource_type\EntityJsonApiResourceType
  */
-class ResourceManager implements ResourceManagerInterface {
+class EntityDeriver extends DeriverBase implements ContainerDeriverInterface {
 
   /**
-   * The entity type manager.
+   * List of derivative definitions.
    *
-   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
+   * @var array
    */
-  protected $entityTypeManager;
+  protected $derivatives;
 
   /**
-   * The configuration factory.
+   * The entity type manager.
    *
-   * @var \Drupal\Core\Config\ConfigFactoryInterface
+   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
    */
-  protected $configFactory;
+  protected $entityTypeManager;
 
   /**
    * The bundle manager.
@@ -37,98 +38,81 @@ class ResourceManager implements ResourceManagerInterface {
   protected $bundleManager;
 
   /**
-   * The module handler.
-   *
-   * @var \Drupal\Core\Extension\ModuleHandlerInterface
-   */
-  protected $moduleHandler;
-
-  /**
-   * The loaded resource config objects.
-   *
-   * @var \Drupal\jsonapi\Configuration\ResourceConfigInterface[]
-   */
-  protected $all = [];
-
-  /**
-   * Instantiates a ResourceManager object.
+   * Constructs an EntityDeriver object.
    *
    * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
    *   The entity type manager.
    * @param \Drupal\Core\Entity\EntityTypeBundleInfoInterface $bundle_manager
    *   The bundle manager.
-   * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
-   *   The config factory interface.
-   * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
-   *   The module handler service.
    */
-  public function __construct(EntityTypeManagerInterface $entity_type_manager, EntityTypeBundleInfoInterface $bundle_manager, ConfigFactoryInterface $config_factory, ModuleHandlerInterface $module_handler) {
+  public function __construct(EntityTypeManagerInterface $entity_type_manager, EntityTypeBundleInfoInterface $bundle_manager) {
     $this->entityTypeManager = $entity_type_manager;
     $this->bundleManager = $bundle_manager;
-    $this->configFactory = $config_factory;
-    $this->moduleHandler = $module_handler;
   }
 
   /**
    * {@inheritdoc}
    */
-  public function all($include_disabled = FALSE) {
-    if (!$this->all) {
-      $entity_type_ids = array_keys($this->entityTypeManager->getDefinitions());
-      foreach ($entity_type_ids as $entity_type_id) {
-        // Add a ResourceConfig per bundle.
-        $this->all = array_merge($this->all, array_map(function ($bundle) use ($entity_type_id) {
-          $resource_config = new ResourceConfig($this->configFactory, $this->entityTypeManager);
-          $resource_config->setEntityTypeId($entity_type_id);
-          $resource_config->setBundleId($bundle);
-          $resource_config->setPath(sprintf('/%s/%s', $entity_type_id, $bundle));
-          $resource_config->setTypeName(sprintf('%s--%s', $entity_type_id, $bundle));
-          return $resource_config;
-        }, array_keys($this->bundleManager->getBundleInfo($entity_type_id))));
-      }
-      // Allow altering the resource configuration. This is used, among other, to
-      // disable resources.
-      $this->moduleHandler->alter('jsonapi_resources', $this->all);
-    }
-    // Filter out the disabled resources if necessary.
-    return $include_disabled ?
-      $this->all :
-      array_filter($this->all, function ($resource) {
-        /* @var \Drupal\jsonapi\Configuration\ResourceConfigInterface $resource */
-        return $resource->isEnabled();
-      });
+  public static function create(ContainerInterface $container, $base_plugin_id) {
+    return new static(
+      $container->get('entity_type.manager'),
+      $container->get('entity_type.bundle.info')
+    );
   }
 
   /**
    * {@inheritdoc}
    */
-  public function get($entity_type_id, $bundle_id) {
-    if (empty($entity_type_id)) {
-      throw new PreconditionFailedHttpException('Server error. The current route is malformed.');
-    }
-    foreach ($this->all(TRUE) as $resource) {
-      if ($resource->getEntityTypeId() == $entity_type_id && $resource->getBundleId() == $bundle_id) {
-        return $resource;
-      }
+  public function getDerivativeDefinitions($base_plugin_definition) {
+    if (isset($this->derivatives)) {
+      return $this->derivatives;
     }
-    return NULL;
-  }
+    $this->derivatives = [];
 
-  /**
-   * {@inheritdoc}
-   */
-  public function getEntityTypeManager() {
-    return $this->entityTypeManager;
-  }
+    $entity_types = $this->entityTypeManager->getDefinitions();
+    foreach ($entity_types as $entity_type_id => $entity_type) {
+      $plugin_definition = [
+        'serialization_class' => $entity_type->getClass(),
+        'route_options' => [
+          'parameters' => [
+            $entity_type_id => [
+              'type' => 'entity:' . $entity_type_id,
+            ],
+          ],
+        ],
+        'route_path_part_for_individual_resource' => $entity_type_id,
+      ] + $base_plugin_definition;
 
-  /**
-   * {@inheritdoc}
-   */
-  public function hasBundle($entity_type_id) {
-    return (bool) $this->getEntityTypeManager()
-      ->getDefinition($entity_type_id)
-      ->getBundleEntityType();
-  }
+      // First derive a JSON API Resource Type for this entity type (this covers
+      // all bundles).
+      $id = sprintf('%s', $entity_type_id);
+      $this->derivatives[$id] = [
+        'id' => $id,
+        'type_hierarchy' => [$entity_type_id],
+        'route_requirements' => [
+          '_entity_type' => $entity_type_id,
+        ],
+      ] + $plugin_definition;
 
+      // Now derive an additional JSON API Resource Type for every bundle that
+      // exists for this entity type.
+      // @todo ensure new bundles are picked up immediately, see \Drupal\Core\Entity\EntityTypeBundleInfo::clearCachedBundles().
+      if ($entity_type->getBundleEntityType() !== NULL) {
+        $bundles = array_keys($this->bundleManager->getBundleInfo($entity_type_id));
+        foreach ($bundles as $bundle) {
+          $id = sprintf('%s.%s', $entity_type_id, $bundle);
+          $this->derivatives[$id] = [
+            'id' => $id,
+            'type_hierarchy' => [$entity_type_id, $bundle],
+            'route_requirements' => [
+              '_entity_type' => $entity_type_id,
+              '_bundle' => $bundle,
+            ],
+          ] + $plugin_definition;
+        }
+      }
+    }
+    return $this->derivatives;
+  }
 
 }
diff --git a/src/Plugin/Deriver/ResourceDeriver.php b/src/Plugin/Deriver/ResourceDeriver.php
deleted file mode 100644
index 3048b62..0000000
--- a/src/Plugin/Deriver/ResourceDeriver.php
+++ /dev/null
@@ -1,82 +0,0 @@
-<?php
-
-namespace Drupal\jsonapi\Plugin\Deriver;
-
-use Drupal\Component\Plugin\Derivative\DeriverBase;
-use Drupal\Core\Plugin\Discovery\ContainerDeriverInterface;
-use Drupal\jsonapi\Configuration\ResourceManagerInterface;
-use Symfony\Component\DependencyInjection\ContainerInterface;
-
-/**
- * Provides a resource plugin definition for every entity type's bundle.
- *
- * @see \Drupal\jsonapi\Plugin\jsonapi\resource\BundleResource
- */
-class ResourceDeriver extends DeriverBase implements ContainerDeriverInterface {
-
-  /**
-   * List of derivative definitions.
-   *
-   * @var array
-   */
-  protected $derivatives;
-
-  /**
-   * The resource manager.
-   *
-   * @var \Drupal\jsonapi\Configuration\ResourceManagerInterface
-   */
-  protected $resourceManager;
-
-  /**
-   * Constructs an ResourceDeriver object.
-   *
-   * @param \Drupal\jsonapi\Configuration\ResourceManagerInterface $resource_manager
-   *   The entity manager.
-   */
-  public function __construct(ResourceManagerInterface $resource_manager) {
-    $this->resourceManager = $resource_manager;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public static function create(ContainerInterface $container, $base_plugin_id) {
-    /* @var \Drupal\jsonapi\Configuration\ResourceManagerInterface $resource_manager */
-    $resource_manager = $container->get('jsonapi.resource.manager');
-    return new static($resource_manager);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getDerivativeDefinitions($base_definition) {
-    if (isset($this->derivatives)) {
-      return $this->derivatives;
-    }
-    $this->derivatives = [];
-    // Add in the default plugin configuration and the resource type.
-    /* @var \Drupal\jsonapi\Configuration\ResourceConfigInterface[] $resource_configs */
-    $resource_configs = $this->resourceManager->all();
-    foreach ($resource_configs as $resource) {
-      $global_config = $resource->getGlobalConfig();
-      $prefix = $global_config->get('prefix');
-      $id = sprintf('%s.dynamic.%s', $prefix, $resource->getTypeName());
-      $this->derivatives[$id] = [
-        'id' => $id,
-        'entityType' => $resource->getEntityTypeId(),
-        'bundle' => $resource->getBundleId(),
-        'hasBundle' => $this->resourceManager->hasBundle($resource->getEntityTypeId()),
-        'type' => $resource->getTypeName(),
-        'data' => [
-          'prefix' => $prefix,
-          'partialPath' => '/' . $prefix . $resource->getPath()
-        ]
-      ];
-
-      $this->derivatives[$id] += $base_definition;
-    }
-    return $this->derivatives;
-  }
-
-}
diff --git a/src/Plugin/JsonApiResourceInterface.php b/src/Plugin/JsonApiResourceInterface.php
deleted file mode 100644
index 560b703..0000000
--- a/src/Plugin/JsonApiResourceInterface.php
+++ /dev/null
@@ -1,14 +0,0 @@
-<?php
-
-namespace Drupal\jsonapi\Plugin;
-
-use Drupal\Component\Plugin\PluginInspectionInterface;
-
-/**
- * Defines an interface for JSON API Resource plugins.
- */
-interface JsonApiResourceInterface extends PluginInspectionInterface {
-
-  // Add get/set methods for your plugin type here.
-
-}
diff --git a/src/Resource/EntityResourceInterface.php b/src/Plugin/JsonApiResourceTypeInterface.php
similarity index 56%
rename from src/Resource/EntityResourceInterface.php
rename to src/Plugin/JsonApiResourceTypeInterface.php
index 4c42bd4..f2708a5 100644
--- a/src/Resource/EntityResourceInterface.php
+++ b/src/Plugin/JsonApiResourceTypeInterface.php
@@ -1,23 +1,20 @@
 <?php
 
+namespace Drupal\jsonapi\Plugin;
 
-namespace Drupal\jsonapi\Resource;
-
-use Drupal\Core\Entity\EntityInterface;
+use Drupal\Component\Plugin\PluginInspectionInterface;
 use Symfony\Component\HttpFoundation\Request;
 
 /**
- * Class EntityResourceInterface.
- *
- * @package Drupal\jsonapi\Resource
+ * Defines an interface for JSON API Resource Type plugins.
  */
-interface EntityResourceInterface {
+interface JsonApiResourceTypeInterface extends PluginInspectionInterface {
 
   /**
-   * Gets the individual entity.
+   * Gets an individual resource object of this resource type.
    *
-   * @param \Drupal\Core\Entity\EntityInterface $entity
-   *   The loaded entity.
+   * @param $object
+   *   A loaded resource object of this type, to return.
    * @param \Symfony\Component\HttpFoundation\Request $request
    *   The request object.
    * @param int $response_code
@@ -26,51 +23,51 @@ interface EntityResourceInterface {
    * @return \Drupal\jsonapi\ResourceResponse
    *   The response.
    */
-  public function getIndividual(EntityInterface $entity, Request $request, $response_code = 200);
+  public function getIndividual($object, Request $request, $response_code = 200);
 
   /**
-   * Creates an individual entity.
+   * Creates an individual resource object of this resource type.
    *
-   * @param \Drupal\Core\Entity\EntityInterface $entity
-   *   The loaded entity.
+   * @param $object
+   *   A loaded resource object of this type, to create.
    * @param \Symfony\Component\HttpFoundation\Request $request
    *   The request object.
    *
    * @return \Drupal\jsonapi\ResourceResponse
    *   The response.
    */
-  public function createIndividual(EntityInterface $entity, Request $request);
+  public function createIndividual($object, Request $request);
 
   /**
-   * Patches an individual entity.
+   * Patches an individual resource object of this resource type.
    *
-   * @param \Drupal\Core\Entity\EntityInterface $entity
-   *   The loaded entity.
-   * @param \Drupal\Core\Entity\EntityInterface $parsed_entity
-   *   The entity with the new data.
+   * @param $object
+   *   A loaded resource object of this type, to patch.
+   * @param $received_object
+   *   A loaded resource object of this type, to patch with.
    * @param \Symfony\Component\HttpFoundation\Request $request
    *   The request object.
    *
    * @return \Drupal\jsonapi\ResourceResponse
    *   The response.
    */
-  public function patchIndividual(EntityInterface $entity, EntityInterface $parsed_entity, Request $request);
+  public function patchIndividual($object, $received_object, Request $request);
 
   /**
-   * Deletes an individual entity.
+   * Deletes an individual resource object of this resource type.
    *
-   * @param \Drupal\Core\Entity\EntityInterface $entity
-   *   The loaded entity.
+   * @param $object
+   *   A loaded resource object of this type, to delete.
    * @param \Symfony\Component\HttpFoundation\Request $request
    *   The request object.
    *
    * @return \Drupal\jsonapi\ResourceResponse
    *   The response.
    */
-  public function deleteIndividual(EntityInterface $entity, Request $request);
+  public function deleteIndividual($object, Request $request);
 
   /**
-   * Gets the collection of entities.
+   * Gets the collection of resource objects of this resource type.
    *
    * @param \Symfony\Component\HttpFoundation\Request $request
    *   The request object.
@@ -83,8 +80,8 @@ interface EntityResourceInterface {
   /**
    * Gets the related resource.
    *
-   * @param \Drupal\Core\Entity\EntityInterface $entity
-   *   The requested entity.
+   * @param $object
+   *   A loaded resource object of this type, to return a related resource for.
    * @param string $related_field
    *   The related field name.
    * @param \Symfony\Component\HttpFoundation\Request $request
@@ -93,13 +90,13 @@ interface EntityResourceInterface {
    * @return \Drupal\jsonapi\ResourceResponse
    *   The response.
    */
-  public function getRelated(EntityInterface $entity, $related_field, Request $request);
+  public function getRelated($object, $related_field, Request $request);
 
   /**
-   * Gets the relationship of an entity.
+   * Gets the relationship of an object.
    *
-   * @param \Drupal\Core\Entity\EntityInterface $entity
-   *   The requested entity.
+   * @param $object
+   *   A loaded resource object of this type, to return a relationship for.
    * @param string $related_field
    *   The related field name.
    * @param \Symfony\Component\HttpFoundation\Request $request
@@ -110,13 +107,13 @@ interface EntityResourceInterface {
    * @return \Drupal\jsonapi\ResourceResponse
    *   The response.
    */
-  public function getRelationship(EntityInterface $entity, $related_field, Request $request, $response_code = 200);
+  public function getRelationship($object, $related_field, Request $request, $response_code = 200);
 
   /**
    * Adds a relationship to a to-many relationship.
    *
-   * @param \Drupal\Core\Entity\EntityInterface $entity
-   *   The requested entity.
+   * @param $object
+   *   A loaded resource object of this type, to create a relationship for.
    * @param string $related_field
    *   The related field name.
    * @param mixed $parsed_field_list
@@ -128,13 +125,13 @@ interface EntityResourceInterface {
    * @return \Drupal\jsonapi\ResourceResponse
    *   The response.
    */
-  public function createRelationship(EntityInterface $entity, $related_field, $parsed_field_list, Request $request);
+  public function createRelationship($object, $related_field, $parsed_field_list, Request $request);
 
   /**
-   * Updates the relationship of an entity.
+   * Updates the relationship of an object.
    *
-   * @param \Drupal\Core\Entity\EntityInterface $entity
-   *   The requested entity.
+   * @param $object
+   *   A loaded resource object of this type, to patch a relationship for.
    * @param string $related_field
    *   The related field name.
    * @param mixed $parsed_field_list
@@ -146,13 +143,13 @@ interface EntityResourceInterface {
    * @return \Drupal\jsonapi\ResourceResponse
    *   The response.
    */
-  public function patchRelationship(EntityInterface $entity, $related_field, $parsed_field_list, Request $request);
+  public function patchRelationship($object, $related_field, $parsed_field_list, Request $request);
 
   /**
    * Deletes the relationship of an entity.
    *
-   * @param \Drupal\Core\Entity\EntityInterface $entity
-   *   The requested entity.
+   * @param $object
+   *   A loaded resource object of this type, to delete a relationship for.
    * @param string $related_field
    *   The related field name.
    * @param mixed $parsed_field_list
@@ -164,6 +161,6 @@ interface EntityResourceInterface {
    * @return \Drupal\jsonapi\ResourceResponse
    *   The response.
    */
-  public function deleteRelationship(EntityInterface $entity, $related_field, $parsed_field_list, Request $request);
+  public function deleteRelationship($object, $related_field, $parsed_field_list, Request $request);
 
 }
diff --git a/src/Plugin/JsonApiResourceManager.php b/src/Plugin/JsonApiResourceTypeManager.php
similarity index 37%
rename from src/Plugin/JsonApiResourceManager.php
rename to src/Plugin/JsonApiResourceTypeManager.php
index 47e0559..f25e749 100644
--- a/src/Plugin/JsonApiResourceManager.php
+++ b/src/Plugin/JsonApiResourceTypeManager.php
@@ -5,27 +5,14 @@ namespace Drupal\jsonapi\Plugin;
 use Drupal\Core\Plugin\DefaultPluginManager;
 use Drupal\Core\Cache\CacheBackendInterface;
 use Drupal\Core\Extension\ModuleHandlerInterface;
-use Drupal\jsonapi\Resource\DocumentWrapperInterface;
-use Drupal\jsonapi\Routing\Routes;
 
 /**
- * Provides the JSON API Resource plugin manager.
+ * Provides the JSON API Resource Type plugin manager.
  */
-class JsonApiResourceManager extends DefaultPluginManager {
+class JsonApiResourceTypeManager extends DefaultPluginManager {
 
   /**
-   * Default values for the plugin definition.
-   *
-   * @var array
-   */
-  protected $defaults = [
-    'permission' => 'access content',
-    'controller' => Routes::FRONT_CONTROLLER,
-    'enabled' => TRUE,
-  ];
-
-  /**
-   * Constructor for JsonApiResourceManager objects.
+   * Constructor for JsonApiResourceTypeManager objects.
    *
    * @param \Traversable $namespaces
    *   An object that implements \Traversable which contains the root paths
@@ -36,10 +23,34 @@ class JsonApiResourceManager extends DefaultPluginManager {
    *   The module handler to invoke the alter hook with.
    */
   public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler) {
-    parent::__construct('Plugin/jsonapi', $namespaces, $module_handler, 'Drupal\jsonapi\Plugin\JsonApiResourceInterface', 'Drupal\jsonapi\Annotation\JsonApiResource');
+    // For now, only allow the JSON API module to provide JSON API Resource Type
+    // plugins. The API is not yet finalized, and it's not yet clear whether it
+    // would make sense to allow additional types beyond entity types and entity
+    // type bundles.
+    $limited_namespaces = new \ArrayObject(['\Drupal\jsonapi' => $namespaces['Drupal\jsonapi']]);
+
+    parent::__construct('Plugin/jsonapi', $limited_namespaces, $module_handler, 'Drupal\jsonapi\Plugin\JsonApiResourceTypeInterface', 'Drupal\jsonapi\Annotation\JsonApiResourceType');
+    $this->setCacheBackend($cache_backend, 'jsonapi_resource_type_plugins');
+  }
+
+  // @todo make more elegant
+  public function getDefinitionByTypeHierarchy($root_type, $sub_type) {
+    $needle = [$root_type];
+    if ($sub_type !== NULL) {
+      $needle[] = $sub_type;
+    }
+
+    foreach ($this->getDefinitions() as $id => $definition) {
+      if ($definition['type_hierarchy'] === $needle) {
+        return $definition;
+      }
+    }
+
+    return NULL;
+  }
 
-    $this->alterInfo('jsonapi_resource_info');
-    $this->setCacheBackend($cache_backend, 'jsonapi_resource_plugins');
+  public function getJsonApiTypeForPlugin($plugin_id) {
+    return implode('--', $this->getDefinition($plugin_id)['type_hierarchy']);
   }
 
 }
diff --git a/src/Plugin/jsonapi/BundleJsonApiResource.php b/src/Plugin/jsonapi/BundleJsonApiResource.php
deleted file mode 100644
index bf97da3..0000000
--- a/src/Plugin/jsonapi/BundleJsonApiResource.php
+++ /dev/null
@@ -1,24 +0,0 @@
-<?php
-
-namespace Drupal\jsonapi\Plugin\jsonapi;
-
-use Drupal\Core\Plugin\ContextAwarePluginBase;
-use Drupal\jsonapi\Plugin\JsonApiResourceBase;
-use Drupal\jsonapi\Plugin\JsonApiResourceInterface;
-
-/**
- * Class BundleJsonApiResource
- *
- * Represents bundles as JSON API resources.
- *
- * @see \Drupal\jsonapi\Plugin\Deriver\ResourceDeriver
- *
- * @JsonApiResource(
- *   id = "bundle",
- *   label = @Translation("Bundle"),
- *   deriver = "Drupal\jsonapi\Plugin\Deriver\ResourceDeriver",
- * )
- *
- * @package Drupal\jsonapi\Plugin\jsonapi
- */
-class BundleJsonApiResource extends ContextAwarePluginBase implements JsonApiResourceInterface {}
diff --git a/src/Resource/EntityResource.php b/src/Plugin/jsonapi/resource_type/EntityJsonApiResourceType.php
similarity index 85%
rename from src/Resource/EntityResource.php
rename to src/Plugin/jsonapi/resource_type/EntityJsonApiResourceType.php
index 6067824..d0e5bfb 100644
--- a/src/Resource/EntityResource.php
+++ b/src/Plugin/jsonapi/resource_type/EntityJsonApiResourceType.php
@@ -1,25 +1,21 @@
 <?php
 
-namespace Drupal\jsonapi\Resource;
+namespace Drupal\jsonapi\Plugin\jsonapi\resource_type;
 
-use Drupal\Component\Serialization\Json;
 use Drupal\Core\Access\AccessibleInterface;
 use Drupal\Core\Config\Entity\ConfigEntityInterface;
 use Drupal\Core\Entity\ContentEntityInterface;
-use Drupal\Core\Entity\EntityFieldManagerInterface;
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Entity\EntityStorageInterface;
-use Drupal\Core\Entity\EntityTypeManagerInterface;
 use Drupal\Core\Entity\FieldableEntityInterface;
 use Drupal\Core\Field\EntityReferenceFieldItemListInterface;
-use Drupal\Core\Field\FieldTypePluginManagerInterface;
 use Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem;
-use Drupal\jsonapi\Configuration\ResourceConfigInterface;
+use Drupal\Core\Plugin\PluginBase;
 use Drupal\jsonapi\EntityCollection;
 use Drupal\jsonapi\EntityCollectionInterface;
 use Drupal\jsonapi\Error\SerializableHttpException;
-use Drupal\jsonapi\Query\QueryBuilderInterface;
-use Drupal\jsonapi\Context\CurrentContextInterface;
+use Drupal\jsonapi\Plugin\JsonApiResourceTypeInterface;
+use Drupal\jsonapi\Resource\DocumentWrapper;
 use Drupal\jsonapi\ResourceResponse;
 use Drupal\jsonapi\Routing\Param\JsonApiParamBase;
 use Drupal\jsonapi\Routing\Param\OffsetPage;
@@ -27,18 +23,17 @@ use Symfony\Component\HttpFoundation\Request;
 use Symfony\Component\HttpFoundation\Response;
 
 /**
- * Class EntityResource.
+ * Represents entity types (and their bundles) as JSON API resource types.
  *
- * @package Drupal\jsonapi\Resource
+ * @see \Drupal\jsonapi\Plugin\Deriver\ResourceDeriver
+ *
+ * @JsonApiResourceType(
+ *   id = "entity",
+ *   label = @Translation("Entity"),
+ *   deriver = "Drupal\jsonapi\Plugin\Deriver\EntityDeriver",
+ * )
  */
-class EntityResource implements EntityResourceInterface {
-
-  /**
-   * The resource config.
-   *
-   * @var \Drupal\jsonapi\Configuration\ResourceConfigInterface
-   */
-  protected $resourceConfig;
+class EntityJsonApiResourceType extends PluginBase implements JsonApiResourceTypeInterface  {
 
   /**
    * The entity type manager.
@@ -48,13 +43,6 @@ class EntityResource implements EntityResourceInterface {
   protected $entityTypeManager;
 
   /**
-   * The field manager.
-   *
-   * @var \Drupal\Core\Entity\EntityFieldManagerInterface
-   */
-  protected $fieldManager;
-
-  /**
    * The query builder service.
    *
    * @var \Drupal\jsonapi\Query\QueryBuilderInterface
@@ -69,41 +57,30 @@ class EntityResource implements EntityResourceInterface {
   protected $currentContext;
 
   /**
-   * The current context service.
-   *
-   * @var \Drupal\Core\Field\FieldTypePluginManagerInterface
+   * {@inheritdoc}
    */
-  protected $pluginManager;
+  public function __construct(array $configuration, $plugin_id, $plugin_definition) {
+    parent::__construct($configuration, $plugin_id, $plugin_definition);
+    $this->entityTypeManager = \Drupal::getContainer()->get('entity_type.manager');
+    $this->queryBuilder = \Drupal::getContainer()->get('jsonapi.query_builder');
+    $this->currentContext = \Drupal::getContainer()->get('jsonapi.current_context');
+  }
 
-  /**
-   * Instantiates a EntityResource object.
-   *
-   * @param \Drupal\jsonapi\Configuration\ResourceConfigInterface $resource_config
-   *   The configuration for the resource.
-   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
-   *   The entity type manager.
-   * @param \Drupal\jsonapi\Query\QueryBuilderInterface $query_builder
-   *   The query builder.
-   * @param \Drupal\Core\Entity\EntityFieldManagerInterface $field_manager
-   *   The entity type field manager.
-   * @param \Drupal\jsonapi\Context\CurrentContextInterface $current_context
-   *   The current context.
-   * @param \Drupal\Core\Field\FieldTypePluginManagerInterface $plugin_manager
-   *   The plugin manager for fields.
-   */
-  public function __construct(ResourceConfigInterface $resource_config, EntityTypeManagerInterface $entity_type_manager, QueryBuilderInterface $query_builder, EntityFieldManagerInterface $field_manager, CurrentContextInterface $current_context, FieldTypePluginManagerInterface $plugin_manager) {
-    $this->resourceConfig = $resource_config;
-    $this->entityTypeManager = $entity_type_manager;
-    $this->queryBuilder = $query_builder;
-    $this->fieldManager = $field_manager;
-    $this->currentContext = $current_context;
-    $this->pluginManager = $plugin_manager;
+  protected function getEntityTypeId() {
+    return $this->getPluginDefinition()['type_hierarchy'][0];
+  }
+
+  protected function getBundle() {
+    $type_hierarchy = $this->getPluginDefinition()['type_hierarchy'];
+    return count($type_hierarchy) == 2 ? $type_hierarchy[1] : NULL;
   }
 
+
   /**
    * {@inheritdoc}
    */
-  public function getIndividual(EntityInterface $entity, Request $request, $response_code = 200) {
+  public function getIndividual($entity, Request $request, $response_code = 200) {
+    assert($entity instanceof EntityInterface);
     $entity_access = $entity->access('view', NULL, TRUE);
     if (!$entity_access->isAllowed()) {
       throw new SerializableHttpException(403, 'The current user is not allowed to GET the selected resource.');
@@ -121,7 +98,8 @@ class EntityResource implements EntityResourceInterface {
    * @throws \Drupal\jsonapi\Error\SerializableHttpException
    *   If validation errors are found.
    */
-  protected function validate(EntityInterface $entity) {
+  protected function validate($entity) {
+    assert($entity instanceof EntityInterface);
     if (!$entity instanceof FieldableEntityInterface) {
       return;
     }
@@ -148,7 +126,8 @@ class EntityResource implements EntityResourceInterface {
   /**
    * {@inheritdoc}
    */
-  public function createIndividual(EntityInterface $entity, Request $request) {
+  public function createIndividual($entity, Request $request) {
+    assert($entity instanceof EntityInterface);
     $entity_access = $entity->access('create', NULL, TRUE);
 
     if (!$entity_access->isAllowed()) {
@@ -162,7 +141,8 @@ class EntityResource implements EntityResourceInterface {
   /**
    * {@inheritdoc}
    */
-  public function patchIndividual(EntityInterface $entity, EntityInterface $parsed_entity, Request $request) {
+  public function patchIndividual($entity, $parsed_entity, Request $request) {
+    assert($entity instanceof EntityInterface);
     $entity_access = $entity->access('update', NULL, TRUE);
     if (!$entity_access->isAllowed()) {
       throw new SerializableHttpException(403, 'The current user is not allowed to GET the selected resource.');
@@ -192,7 +172,8 @@ class EntityResource implements EntityResourceInterface {
   /**
    * {@inheritdoc}
    */
-  public function deleteIndividual(EntityInterface $entity, Request $request) {
+  public function deleteIndividual($entity, Request $request) {
+    assert($entity instanceof EntityInterface);
     $entity_access = $entity->access('delete', NULL, TRUE);
     if (!$entity_access->isAllowed()) {
       throw new SerializableHttpException(403, 'The current user is not allowed to DELETE the selected resource.');
@@ -206,7 +187,7 @@ class EntityResource implements EntityResourceInterface {
    */
   public function getCollection(Request $request) {
     // Instantiate the query for the filtering.
-    $entity_type_id = $this->resourceConfig->getEntityTypeId();
+    $entity_type_id = $this->getEntityTypeId();
 
     // Set the current context from the request.
     $this->currentContext->fromRequest($request);
@@ -242,7 +223,8 @@ class EntityResource implements EntityResourceInterface {
   /**
    * {@inheritdoc}
    */
-  public function getRelated(EntityInterface $entity, $related_field, Request $request) {
+  public function getRelated($entity, $related_field, Request $request) {
+    assert($entity instanceof EntityInterface);
     /* @var $field_list \Drupal\Core\Field\FieldItemListInterface */
     if (!($field_list = $entity->get($related_field)) || !$this->isRelationshipField($field_list)) {
       throw new SerializableHttpException(404, sprintf('The relationship %s is not present in this resource.', $related_field));
@@ -266,7 +248,8 @@ class EntityResource implements EntityResourceInterface {
   /**
    * {@inheritdoc}
    */
-  public function getRelationship(EntityInterface $entity, $related_field, Request $request, $response_code = 200) {
+  public function getRelationship($entity, $related_field, Request $request, $response_code = 200) {
+    assert($entity instanceof EntityInterface);
     if (!($field_list = $entity->get($related_field)) || !$this->isRelationshipField($field_list)) {
       throw new SerializableHttpException(404, sprintf('The relationship %s is not present in this resource.', $related_field));
     }
@@ -277,7 +260,8 @@ class EntityResource implements EntityResourceInterface {
   /**
    * {@inheritdoc}
    */
-  public function createRelationship(EntityInterface $entity, $related_field, $parsed_field_list, Request $request) {
+  public function createRelationship($entity, $related_field, $parsed_field_list, Request $request) {
+    assert($entity instanceof EntityInterface);
     if ($parsed_field_list instanceof Response) {
       // This usually means that there was an error, so there is no point on
       // processing further.
@@ -312,7 +296,8 @@ class EntityResource implements EntityResourceInterface {
   /**
    * {@inheritdoc}
    */
-  public function patchRelationship(EntityInterface $entity, $related_field, $parsed_field_list, Request $request) {
+  public function patchRelationship($entity, $related_field, $parsed_field_list, Request $request) {
+    assert($entity instanceof EntityInterface);
     if ($parsed_field_list instanceof Response) {
       // This usually means that there was an error, so there is no point on
       // processing further.
@@ -371,7 +356,8 @@ class EntityResource implements EntityResourceInterface {
   /**
    * {@inheritdoc}
    */
-  public function deleteRelationship(EntityInterface $entity, $related_field, $parsed_field_list, Request $request) {
+  public function deleteRelationship($entity, $related_field, $parsed_field_list, Request $request) {
+    assert($entity instanceof EntityInterface);
     if ($parsed_field_list instanceof Response) {
       // This usually means that there was an error, so there is no point on
       // processing further.
@@ -420,10 +406,10 @@ class EntityResource implements EntityResourceInterface {
     $query = $this->queryBuilder->newQuery($entity_type, $params);
 
     // Limit this query to the bundle type for this resource.
-    $bundle_id = $this->resourceConfig->getBundleId();
-    if ($bundle_id && ($bundle_key = $entity_type->getKey('bundle'))) {
+    $bundle = $this->getBundle();
+    if ($bundle && ($bundle_key = $entity_type->getKey('bundle'))) {
       $query->condition(
-        $bundle_key, $bundle_id
+        $bundle_key, $bundle
       );
     }
 
diff --git a/src/Relationship.php b/src/Relationship.php
index c8350d5..271f384 100644
--- a/src/Relationship.php
+++ b/src/Relationship.php
@@ -39,13 +39,6 @@ class Relationship implements RelationshipInterface, AccessibleInterface {
   protected $propertyName;
 
   /**
-   * The resource manager.
-   *
-   * @var \Drupal\jsonapi\Configuration\ResourceManagerInterface
-   */
-  protected $resourceManager;
-
-  /**
    * The relationship items.
    *
    * @var array
@@ -55,8 +48,6 @@ class Relationship implements RelationshipInterface, AccessibleInterface {
   /**
    * Relationship constructor.
    *
-   * @param \Drupal\jsonapi\Configuration\ResourceManagerInterface $resource_manager
-   *   The resource manager.
    * @param string $field_name
    *   The name of the relationship.
    * @param int $cardinality
@@ -68,15 +59,14 @@ class Relationship implements RelationshipInterface, AccessibleInterface {
    * @param string $target_key
    *   The property name of the relationship id.
    */
-  public function __construct(ResourceManagerInterface $resource_manager, $field_name, $cardinality = FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED, EntityCollectionInterface $entities, EntityInterface $host_entity, $target_key = 'target_id') {
-    $this->resourceManager = $resource_manager;
+  public function __construct($field_name, $cardinality = FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED, EntityCollectionInterface $entities, EntityInterface $host_entity, $target_key = 'target_id') {$this->resourceManager = $resource_manager;
     $this->propertyName = $field_name;
     $this->cardinality = $cardinality;
     $this->hostEntity = $host_entity;
     $this->items = [];
     foreach ($entities as $entity) {
       $this->items[] = new RelationshipItem(
-        $resource_manager,
+        \Drupal::getContainer()->get('plugin.manager.jsonapi.resource_type'),
         $entity,
         $this,
         $target_key
diff --git a/src/RelationshipItem.php b/src/RelationshipItem.php
index a303205..b5a0696 100644
--- a/src/RelationshipItem.php
+++ b/src/RelationshipItem.php
@@ -4,6 +4,7 @@ namespace Drupal\jsonapi;
 
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\jsonapi\Configuration\ResourceManagerInterface;
+use Drupal\jsonapi\Plugin\JsonApiResourceTypeManager;
 
 class RelationshipItem implements RelationshipItemInterface {
 
@@ -47,10 +48,12 @@ class RelationshipItem implements RelationshipItemInterface {
    * @param string $target_key
    *   The key name of the target relationship.
    */
-  public function __construct(ResourceManagerInterface $resource_manager, EntityInterface $target_entity, RelationshipInterface $parent, $target_key = 'target_id') {
-    $this->targetResourceConfig = $resource_manager->get(
+  public function __construct(JsonApiResourceTypeManager $jsonapi_resource_type_manager, EntityInterface $target_entity, RelationshipInterface $parent, $target_key = 'target_id') {
+    $this->targetResourceConfig = $jsonapi_resource_type_manager->getDefinitionByTypeHierarchy(
       $target_entity->getEntityTypeId(),
-      $target_entity->bundle()
+      $target_entity->getEntityType()->getBundleEntityType() === NULL
+        ? NULL
+        : $target_entity->bundle()
     );
     $this->targetKey = $target_key;
     $this->targetEntity = $target_entity;
@@ -75,9 +78,8 @@ class RelationshipItem implements RelationshipItemInterface {
    * {@inheritdoc}
    */
   public function getValue() {
-    $method = $this->getTargetResourceConfig()->getIdKey() == 'uuid' ?
-      'uuid' :
-      'id';
+    // @todo
+    $method = 'uuid';
     return [$this->targetKey => $this->getTargetEntity()->{$method}()];
   }
 
@@ -88,11 +90,4 @@ class RelationshipItem implements RelationshipItemInterface {
     return $this->parent;
   }
 
-  /**
-   * {@inheritdoc}
-   */
-  public function resourceIsEnabled() {
-    return $this->getTargetResourceConfig()->isEnabled();
-  }
-
 }
diff --git a/src/RelationshipItemInterface.php b/src/RelationshipItemInterface.php
index 2f87206..c996e01 100644
--- a/src/RelationshipItemInterface.php
+++ b/src/RelationshipItemInterface.php
@@ -34,12 +34,4 @@ interface RelationshipItemInterface {
    */
   public function getParent();
 
-  /**
-   * Is the target resource enabled?
-   *
-   * @return bool
-   *   TRUE if the resource is enabled. FALSE otherwise.
-   */
-  public function resourceIsEnabled();
-
 }
diff --git a/src/RequestHandler.php b/src/RequestHandler.php
index bef31ab..54a97b6 100644
--- a/src/RequestHandler.php
+++ b/src/RequestHandler.php
@@ -8,6 +8,7 @@ use Drupal\Core\Routing\RouteMatchInterface;
 use Drupal\jsonapi\Context\CurrentContextInterface;
 use Drupal\jsonapi\Error\ErrorHandlerInterface;
 use Drupal\jsonapi\Error\SerializableHttpException;
+use Drupal\jsonapi\Plugin\JsonApiResourceTypeManager;
 use Drupal\jsonapi\Resource\EntityResource;
 use Symfony\Component\DependencyInjection\ContainerAwareInterface;
 use Symfony\Component\DependencyInjection\ContainerAwareTrait;
@@ -31,10 +32,22 @@ class RequestHandler implements ContainerAwareInterface, ContainerInjectionInter
    * {@inheritdoc}
    */
   public static function create(ContainerInterface $container) {
-    return new static($container->get('entity_type.manager')->getStorage('rest_resource_config'));
+    return new static(
+      $container->get('plugin.manager.jsonapi.resource_type')
+    );
   }
 
   /**
+   * @var \Drupal\jsonapi\Plugin\JsonApiResourceTypeManager
+   */
+  protected $jsonApiResourceTypeManager;
+
+  public function __construct(JsonApiResourceTypeManager $jsonapi_resource_type_manager) {
+    $this->jsonApiResourceTypeManager = $jsonapi_resource_type_manager;
+  }
+
+
+    /**
    * Handles a web API request.
    *
    * @param \Drupal\Core\Routing\RouteMatchInterface $route_match
@@ -77,7 +90,9 @@ class RequestHandler implements ContainerAwareInterface, ContainerInjectionInter
     // parsing it out of the Accept headers again, we can simply retrieve the
     // format requirement. If there is no format associated, just pick JSON.
     $action = $this->action($route_match, $method);
-    $resource = $this->resourceFactory($route, $current_context);
+
+    $jsonapi_plugin_id = $route->getOption('_jsonapi_plugin_id');
+    $resource = $this->jsonApiResourceTypeManager->createInstance($jsonapi_plugin_id);
 
     // Only add the unserialized data if there is something there.
     $extra_parameters = $unserialized ? [$unserialized, $request] : [$request];
diff --git a/src/Routing/Routes.php b/src/Routing/Routes.php
index 2cd1413..6d6634d 100644
--- a/src/Routing/Routes.php
+++ b/src/Routing/Routes.php
@@ -4,8 +4,10 @@ namespace Drupal\jsonapi\Routing;
 
 use Drupal\Core\Authentication\AuthenticationCollectorInterface;
 use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
+use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
+use Drupal\Core\Entity\EntityTypeManagerInterface;
 use Drupal\Core\Field\EntityReferenceFieldItemList;
-use Drupal\jsonapi\Plugin\JsonApiResourceManager;
+use Drupal\jsonapi\Plugin\JsonApiResourceTypeManager;
 use Drupal\jsonapi\Resource\DocumentWrapperInterface;
 use Symfony\Cmf\Component\Routing\RouteObjectInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -27,11 +29,23 @@ class Routes implements ContainerInjectionInterface {
   const FRONT_CONTROLLER = '\Drupal\jsonapi\RequestHandler::handle';
 
   /**
-   * The resource manager interface.
+   * @var \Drupal\jsonapi\Plugin\JsonApiResourceTypeManager
+   */
+  protected $jsonApiResourceTypeManager;
+
+  /**
+   * The entity type manager.
+   *
+   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
+   */
+  protected $entityTypeManager;
+
+  /**
+   * The bundle manager.
    *
-   * @var \Drupal\jsonapi\Plugin\JsonApiResourceManager
+   * @var \Drupal\Core\Entity\EntityTypeBundleInfoInterface
    */
-  protected $resourcePluginManager;
+  protected $bundleManager;
 
   /**
    * The authentication collector.
@@ -41,7 +55,7 @@ class Routes implements ContainerInjectionInterface {
   protected $authCollector;
 
   /**
-   * List of providers.
+   * List of authentication provider IDs.
    *
    * @var string[]
    */
@@ -50,13 +64,17 @@ class Routes implements ContainerInjectionInterface {
   /**
    * Instantiates a Routes object.
    *
-   * @param \Drupal\jsonapi\Plugin\JsonApiResourceManager $resource_plugin_manager
-   *   The resource manager.
+   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
+   *   The entity type manager.
+   * @param \Drupal\Core\Entity\EntityTypeBundleInfoInterface $bundle_manager
+   *   The bundle manager.
    * @param \Drupal\Core\Authentication\AuthenticationCollectorInterface $auth_collector
-   *   The resource manager.
+   *   The authentication collector.
    */
-  public function __construct(JsonApiResourceManager $resource_plugin_manager, AuthenticationCollectorInterface $auth_collector) {
-    $this->resourcePluginManager = $resource_plugin_manager;
+  public function __construct(JsonApiResourceTypeManager $json_api_resource_type_manager, EntityTypeManagerInterface $entity_type_manager, EntityTypeBundleInfoInterface $bundle_manager, AuthenticationCollectorInterface $auth_collector) {
+    $this->jsonApiResourceTypeManager = $json_api_resource_type_manager;
+    $this->entityTypeManager = $entity_type_manager;
+    $this->bundleManager = $bundle_manager;
     $this->authCollector = $auth_collector;
   }
 
@@ -64,12 +82,12 @@ class Routes implements ContainerInjectionInterface {
    * {@inheritdoc}
    */
   public static function create(ContainerInterface $container) {
-    /* @var \Drupal\jsonapi\Plugin\JsonApiResourceManager $resource_plugin_manager */
-    $resource_plugin_manager = $container->get('plugin.manager.resource.processor');
-    /* @var \Drupal\Core\Authentication\AuthenticationCollectorInterface $auth_collector */
-    $auth_collector = $container->get('authentication_collector');
-
-    return new static($resource_plugin_manager, $auth_collector);
+    return new static(
+      $container->get('plugin.manager.jsonapi.resource_type'),
+      $container->get('entity_type.manager'),
+      $container->get('entity_type.bundle.info'),
+      $container->get('authentication_collector')
+    );
   }
 
   /**
@@ -77,19 +95,14 @@ class Routes implements ContainerInjectionInterface {
    */
   public function routes() {
     $collection = new RouteCollection();
-    foreach ($this->resourcePluginManager->getDefinitions() as $plugin_id => $plugin_definition) {
-      if (empty($plugin_definition['enabled'])) {
-        continue;
-      }
-      $entity_type = $plugin_definition['entityType'];
-      // For the entity type resources the bundle is NULL.
-      $bundle = $plugin_definition['bundle'];
-      $partial_path = $plugin_definition['data']['partialPath'];
-      $route_keys = explode(':', $plugin_id);
-      $route_key = end($route_keys) . '.';
+
+    foreach ($this->jsonApiResourceTypeManager->getDefinitions() as $id => $definition) {
+      $route_name_prefix = 'jsonapi.' . implode('.', $definition['type_hierarchy']);
+      $path_prefix = '/api/' . implode('/', $definition['type_hierarchy']);
+
       // Add the collection route.
       $defaults = [
-        RouteObjectInterface::CONTROLLER_NAME => $plugin_definition['controller'],
+        RouteObjectInterface::CONTROLLER_NAME => static::FRONT_CONTROLLER,
       ];
       // Options that apply to all routes.
       $options = [
@@ -98,70 +111,57 @@ class Routes implements ContainerInjectionInterface {
       ];
 
       // Collection endpoint, like /api/file/photo.
-      $route_collection = (new Route($partial_path))
+      $route_collection = (new Route($path_prefix))
         ->addDefaults($defaults)
-        ->setRequirement('_entity_type', $entity_type)
-        ->setRequirement('_permission', $plugin_definition['permission'])
+        ->addRequirements($definition['route_requirements'])
         ->setRequirement('_format', 'api_json')
         ->setRequirement('_custom_parameter_names', 'TRUE')
+        ->setOption('_jsonapi_plugin_id', $id)
         ->setOption('serialization_class', DocumentWrapperInterface::class)
         ->setMethods(['GET', 'POST']);
-      if ($bundle) {
-        $route_collection->setRequirement('_bundle', $bundle);
-      }
       $route_collection->addOptions($options);
-      $collection->add($route_key . 'collection', $route_collection);
+      $collection->add($route_name_prefix . '.collection', $route_collection);
 
       // Individual endpoint, like /api/file/photo/123.
-      $parameters = [$entity_type => ['type' => 'entity:' . $entity_type]];
-      $route_individual = (new Route(sprintf('%s/{%s}', $partial_path, $entity_type)))
+      $route_individual = (new Route(sprintf('%s/{%s}', $path_prefix, $definition['route_path_part_for_individual_resource'])))
         ->addDefaults($defaults)
-        ->setRequirement('_entity_type', $entity_type)
-        ->setRequirement('_permission', $plugin_definition['permission'])
+        ->addRequirements($definition['route_requirements'])
         ->setRequirement('_format', 'api_json')
         ->setRequirement('_custom_parameter_names', 'TRUE')
-        ->setOption('parameters', $parameters)
+        ->addOptions($definition['route_options'])
+        ->setOption('_jsonapi_plugin_id', $id)
         ->setOption('_auth', $this->authProviderList())
         ->setOption('serialization_class', DocumentWrapperInterface::class)
         ->setMethods(['GET', 'PATCH', 'DELETE']);
-      if ($bundle) {
-        $route_individual->setRequirement('_bundle', $bundle);
-      }
       $route_individual->addOptions($options);
-      $collection->add($route_key . 'individual', $route_individual);
+      $collection->add($route_name_prefix . '.individual', $route_individual);
 
       // Related resource, like /api/file/photo/123/comments.
-      $route_related = (new Route(sprintf('%s/{%s}/{related}', $partial_path, $entity_type)))
+      $route_related = (new Route(sprintf('%s/{%s}/{related}', $path_prefix, $definition['route_path_part_for_individual_resource'])))
         ->addDefaults($defaults)
-        ->setRequirement('_entity_type', $entity_type)
-        ->setRequirement('_permission', $plugin_definition['permission'])
+        ->addRequirements($definition['route_requirements'])
         ->setRequirement('_format', 'api_json')
         ->setRequirement('_custom_parameter_names', 'TRUE')
-        ->setOption('parameters', $parameters)
+        ->addOptions($definition['route_options'])
+        ->setOption('_jsonapi_plugin_id', $id)
         ->setOption('_auth', $this->authProviderList())
         ->setMethods(['GET']);
-      if ($bundle) {
-        $route_related->setRequirement('_bundle', $bundle);
-      }
       $route_related->addOptions($options);
-      $collection->add($route_key . 'related', $route_related);
+      $collection->add($route_name_prefix . '.related', $route_related);
 
       // Related endpoint, like /api/file/photo/123/relationships/comments.
-      $route_relationship = (new Route(sprintf('%s/{%s}/relationships/{related}', $partial_path, $entity_type)))
+      $route_relationship = (new Route(sprintf('%s/{%s}/relationships/{related}', $path_prefix, $definition['route_path_part_for_individual_resource'])))
         ->addDefaults($defaults + ['_on_relationship' => TRUE])
-        ->setRequirement('_entity_type', $entity_type)
-        ->setRequirement('_permission', $plugin_definition['permission'])
+        ->addRequirements($definition['route_requirements'])
         ->setRequirement('_format', 'api_json')
         ->setRequirement('_custom_parameter_names', 'TRUE')
-        ->setOption('parameters', $parameters)
+        ->addOptions($definition['route_options'])
+        ->setOption('_jsonapi_plugin_id', $id)
         ->setOption('_auth', $this->authProviderList())
         ->setOption('serialization_class', EntityReferenceFieldItemList::class)
         ->setMethods(['GET', 'POST', 'PATCH', 'DELETE']);
-      if ($bundle) {
-        $route_relationship->setRequirement('_bundle', $bundle);
-      }
       $route_relationship->addOptions($options);
-      $collection->add($route_key . 'relationship', $route_relationship);
+      $collection->add($route_name_prefix . '.relationship', $route_relationship);
     }
 
     return $collection;
diff --git a/tests/src/Kernel/Configuration/ResourceManagerTest.php b/tests/src/Kernel/Configuration/ResourceManagerTest.php
index 0d3e1ee..d25b195 100644
--- a/tests/src/Kernel/Configuration/ResourceManagerTest.php
+++ b/tests/src/Kernel/Configuration/ResourceManagerTest.php
@@ -3,7 +3,7 @@
 namespace Drupal\Tests\jsonapi\Kernel\Configuration;
 
 use Drupal\jsonapi\Configuration\ResourceConfigInterface;
-use Drupal\jsonapi\Configuration\ResourceManager;
+use Drupal\jsonapi\Configuration\JsonApiResourceRepository;
 use Drupal\KernelTests\KernelTestBase;
 use Drupal\node\Entity\NodeType;
 
diff --git a/tests/src/Unit/Routing/RoutesTest.php b/tests/src/Unit/Routing/RoutesTest.php
index b2e5d1b..5c0996c 100644
--- a/tests/src/Unit/Routing/RoutesTest.php
+++ b/tests/src/Unit/Routing/RoutesTest.php
@@ -3,7 +3,7 @@
 namespace Drupal\Tests\jsonapi\Unit\Routing;
 
 use Drupal\Core\Authentication\AuthenticationCollectorInterface;
-use Drupal\jsonapi\Plugin\JsonApiResourceManager;
+use Drupal\jsonapi\Plugin\JsonApiResourceTypeManager;
 use Drupal\jsonapi\Routing\Routes;
 use Drupal\Tests\UnitTestCase;
 use Symfony\Cmf\Component\Routing\RouteObjectInterface;
