 composer.json                                      |   2 +-
 jsonapi_extras.services.yml                        |   7 ++
 src/Entity/JsonapiResourceConfig.php               |  17 +++-
 src/EventSubscriber/ConfigSubscriber.php           | 101 +++++++++++++++++++++
 src/JsonapiExtrasServiceProvider.php               |   5 +
 src/Normalizer/EntityNormalizerTrait.php           |  23 -----
 .../ConfigurableResourceTypeRepository.php         |  10 +-
 7 files changed, 133 insertions(+), 32 deletions(-)

diff --git a/composer.json b/composer.json
index 2125c65..840bc4b 100644
--- a/composer.json
+++ b/composer.json
@@ -11,7 +11,7 @@
     ],
     "require": {
         "drupal/core": "^8.5",
-        "drupal/jsonapi": "^1.13",
+        "drupal/jsonapi": "1.x-dev#a743765058eebead7d8bef2191597c34b8b1da2f",
         "e0ipso/shaper": "^1"
     }
 }
diff --git a/jsonapi_extras.services.yml b/jsonapi_extras.services.yml
index 627c7a2..0f8936a 100644
--- a/jsonapi_extras.services.yml
+++ b/jsonapi_extras.services.yml
@@ -22,3 +22,10 @@ services:
   plugin.manager.resource_field_enhancer:
     class: Drupal\jsonapi_extras\Plugin\ResourceFieldEnhancerManager
     parent: default_plugin_manager
+
+  # Event subscribers.
+  jsonapi_extras.config_subscriber:
+    class: Drupal\jsonapi_extras\EventSubscriber\ConfigSubscriber
+    arguments: ['@kernel', '@router.builder']
+    tags:
+      - { name: event_subscriber }
diff --git a/src/Entity/JsonapiResourceConfig.php b/src/Entity/JsonapiResourceConfig.php
index d918feb..51cbb03 100644
--- a/src/Entity/JsonapiResourceConfig.php
+++ b/src/Entity/JsonapiResourceConfig.php
@@ -74,8 +74,15 @@ class JsonapiResourceConfig extends ConfigEntityBase {
    */
   public function postSave(EntityStorageInterface $storage, $update = TRUE) {
     parent::postSave($storage, $update);
+    static::rebuildRoutes();
+  }
 
-    \Drupal::service('router.builder')->setRebuildNeeded();
+  /**
+   * {@inheritdoc}
+   */
+  public static function postDelete(EntityStorageInterface $storage, array $entities) {
+    parent::postDelete($storage, $entities);
+    static::rebuildRoutes();
   }
 
   /**
@@ -103,4 +110,12 @@ class JsonapiResourceConfig extends ConfigEntityBase {
     return $uri_route_parameters;
   }
 
+  /**
+   * Triggers rebuilding of JSON API routes.
+   */
+  protected static function rebuildRoutes() {
+    \Drupal::service('jsonapi.resource_type.repository')->reset();
+    \Drupal::service('router.builder')->setRebuildNeeded();
+  }
+
 }
diff --git a/src/EventSubscriber/ConfigSubscriber.php b/src/EventSubscriber/ConfigSubscriber.php
new file mode 100644
index 0000000..23faf6e
--- /dev/null
+++ b/src/EventSubscriber/ConfigSubscriber.php
@@ -0,0 +1,101 @@
+<?php
+
+namespace Drupal\jsonapi_extras\EventSubscriber;
+
+use Drupal\Core\Cache\CacheableResponseInterface;
+use Drupal\Core\Config\ConfigCrudEvent;
+use Drupal\Core\Config\ConfigEvents;
+use Drupal\Core\DrupalKernelInterface;
+use Drupal\Core\Routing\RouteBuilderInterface;
+use Symfony\Component\EventDispatcher\EventSubscriberInterface;
+use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
+use Symfony\Component\HttpKernel\KernelEvents;
+
+/**
+ * Associates config cache tag and rebuilds container + routes when necessary.
+ */
+class ConfigSubscriber implements EventSubscriberInterface {
+
+  /**
+   * The Drupal kernel.
+   *
+   * @var \Drupal\Core\DrupalKernelInterface
+   */
+  protected $drupalKernel;
+
+  /**
+   * The route building service.
+   *
+   * @var \Drupal\Core\Routing\RouteBuilderInterface
+   */
+  protected $routeBuilder;
+
+  /**
+   * Constructs a ConfigSubscriber object.
+   *
+   * @param \Drupal\Core\DrupalKernelInterface $drupal_kernel
+   *   The Drupal kernel.
+   * @param \Drupal\Core\Routing\RouteBuilderInterface $route_builder
+   *   The route building service.
+   */
+  public function __construct(DrupalKernelInterface $drupal_kernel, RouteBuilderInterface $route_builder) {
+    $this->drupalKernel = $drupal_kernel;
+    $this->routeBuilder = $route_builder;
+  }
+
+  /**
+   * Rebuilds container and routes  when 'path_prefix' configuration is changed.
+   *
+   * @param \Drupal\Core\Config\ConfigCrudEvent $event
+   *   The Event to process.
+   */
+  public function onSave(ConfigCrudEvent $event) {
+    if ($event->getConfig()->getName() === 'jsonapi_extras.settings') {
+      // @see \Drupal\jsonapi_extras\JsonapiExtrasServiceProvider::alter()
+      if ($event->isChanged('path_prefix')) {
+        $this->drupalKernel->rebuildContainer();
+        $container = \Drupal::getContainer();
+        // Because \Drupal\jsonapi\Routing\Routes::routes() uses a container
+        // parameter, we need to ensure that it uses the freshly rebuilt
+        // container. Due to that, it's impossible to use an injected route
+        // builder service, at least until core updates it to support
+        // \Drupal\Core\DrupalKernelInterface::CONTAINER_INITIALIZE_SUBREQUEST_FINISHED
+        $this->service = $container->get('router.builder');
+        $container->get('router.builder')->rebuild();
+      }
+    }
+  }
+
+  /**
+   * Associates JSON API Extras' config cache tag with all JSON API responses.
+   * @param \Symfony\Component\HttpKernel\Event\FilterResponseEvent $event
+   */
+  public function onResponse(FilterResponseEvent $event) {
+    if ($event->getRequest()->getRequestFormat() !== 'api_json') {
+      return;
+    }
+
+    $response = $event->getResponse();
+    if (!$response instanceof CacheableResponseInterface) {
+      return;
+    }
+
+    $response->getCacheableMetadata()
+      ->addCacheTags([
+        'config:jsonapi_extras.settings',
+        'config:jsonapi_resource_config_list',
+      ]);
+  }
+
+    /**
+   * {@inheritdoc}
+   */
+  public static function getSubscribedEvents() {
+    $events[ConfigEvents::SAVE][] = ['onSave'];
+    // Run before \Drupal\jsonapi\EventSubscriber\ResourceResponseSubscriber::onResponse()
+    // (priority 128), so we can add JSON API's config cache tag.
+    $events[KernelEvents::RESPONSE][] = ['onResponse', 150];
+    return $events;
+  }
+
+}
diff --git a/src/JsonapiExtrasServiceProvider.php b/src/JsonapiExtrasServiceProvider.php
index 7ca2ffe..f6e0527 100644
--- a/src/JsonapiExtrasServiceProvider.php
+++ b/src/JsonapiExtrasServiceProvider.php
@@ -2,6 +2,7 @@
 
 namespace Drupal\jsonapi_extras;
 
+use Drupal\Core\Config\BootstrapConfigStorageFactory;
 use Drupal\Core\DependencyInjection\ContainerBuilder;
 use Drupal\Core\DependencyInjection\ServiceProviderBase;
 use Drupal\jsonapi_extras\ResourceType\ConfigurableResourceTypeRepository;
@@ -26,6 +27,10 @@ class JsonapiExtrasServiceProvider extends ServiceProviderBase {
       $definition->addArgument(new Reference('plugin.manager.resource_field_enhancer'));
       $definition->addArgument(new Reference('config.factory'));
     }
+
+    $settings = BootstrapConfigStorageFactory::get()
+      ->read('jsonapi_extras.settings');
+    $container->setParameter('jsonapi.base_path', '/' . $settings['path_prefix']);
   }
 
   /**
diff --git a/src/Normalizer/EntityNormalizerTrait.php b/src/Normalizer/EntityNormalizerTrait.php
index 15821f6..8c10462 100644
--- a/src/Normalizer/EntityNormalizerTrait.php
+++ b/src/Normalizer/EntityNormalizerTrait.php
@@ -66,29 +66,6 @@ trait EntityNormalizerTrait {
   }
 
   /**
-   * {@inheritdoc}
-   */
-  public function normalize($entity, $format = NULL, array $context = []) {
-    $output = parent::normalize($entity, $format, $context);
-
-    /** @var \Drupal\jsonapi\ResourceType\ResourceType $resource_type */
-    $resource_type = $context['resource_type'];
-    $entity_type_id = $resource_type->getEntityTypeId();
-    $bundle_id = $resource_type->getBundle();
-    // The output depends on the configuration entity for caching.
-    if ($resource_config = $this->getResourceConfig($entity_type_id, $bundle_id)) {
-      $context['cacheable_metadata']->addCacheableDependency(
-        $resource_config
-      );
-    }
-    $context['cacheable_metadata']->addCacheableDependency(
-      \Drupal::config('jsonapi_extras.settings')
-    );
-
-    return $output;
-  }
-
-  /**
    * Get the configuration entity based on the entity type and bundle.
    *
    * @param string $entity_type_id
diff --git a/src/ResourceType/ConfigurableResourceTypeRepository.php b/src/ResourceType/ConfigurableResourceTypeRepository.php
index 135b42f..bee2f5f 100644
--- a/src/ResourceType/ConfigurableResourceTypeRepository.php
+++ b/src/ResourceType/ConfigurableResourceTypeRepository.php
@@ -165,13 +165,9 @@ class ConfigurableResourceTypeRepository extends ResourceTypeRepository {
     }, []);
   }
 
-  /**
-   * {@inheritdoc}
-   */
-  public function getPathPrefix() {
-    return $this->configFactory
-      ->get('jsonapi_extras.settings')
-      ->get('path_prefix');
+  public function reset() {
+    $this->all = NULL;
+    $this->resourceConfigs = NULL;
   }
 
 }
