diff --git a/tests/src/Functional/JsonApiFunctionalTest.php b/tests/src/Functional/JsonApiFunctionalTest.php
index 61b1cea..81a9596 100644
--- a/tests/src/Functional/JsonApiFunctionalTest.php
+++ b/tests/src/Functional/JsonApiFunctionalTest.php
@@ -699,9 +699,8 @@ class JsonApiFunctionalTest extends JsonApiFunctionalTestBase {
         ],
       ],
     ];
-    $relationship_url = Url::fromRoute('jsonapi.node--article.relationship', [
+    $relationship_url = Url::fromRoute('jsonapi.node--article.relationship.field_tags', [
       'node' => $uuid,
-      'related' => 'field_tags',
     ]);
     $response = $this->request('POST', $relationship_url, [
       'body' => Json::encode($body),
diff --git a/tests/src/Kernel/Context/FieldResolverTest.php b/tests/src/Kernel/Context/FieldResolverTest.php
index 5d2926e..5da37fd 100644
--- a/tests/src/Kernel/Context/FieldResolverTest.php
+++ b/tests/src/Kernel/Context/FieldResolverTest.php
@@ -16,7 +16,13 @@ use Drupal\Tests\jsonapi\Kernel\JsonapiKernelTestBase;
  */
 class FieldResolverTest extends JsonapiKernelTestBase {
 
-  public static $modules = ['entity_test', 'serialization', 'field', 'text'];
+  public static $modules = [
+    'entity_test',
+    'serialization',
+    'field',
+    'text',
+    'user',
+  ];
 
   /**
    * The subject under test.
diff --git a/tests/src/Kernel/Controller/EntryPointTest.php b/tests/src/Kernel/Controller/EntryPointTest.php
index 25ebd83..7e71bff 100644
--- a/tests/src/Kernel/Controller/EntryPointTest.php
+++ b/tests/src/Kernel/Controller/EntryPointTest.php
@@ -4,6 +4,8 @@ namespace Drupal\Tests\jsonapi\Kernel\Controller;
 
 use Drupal\Core\Cache\CacheableJsonResponse;
 use Drupal\jsonapi\Controller\EntryPoint;
+use Drupal\jsonapi\ResourceType\ResourceType;
+use Drupal\jsonapi\ResourceType\ResourceTypeRepositoryInterface;
 use Drupal\Tests\jsonapi\Kernel\JsonapiKernelTestBase;
 
 /**
@@ -27,24 +29,72 @@ class EntryPointTest extends JsonapiKernelTestBase {
   ];
 
   /**
-   * @covers ::index
+   * The subject under test.
+   *
+   * @var \Drupal\jsonapi\Controller\EntryPoint
+   */
+  protected $entryPoint;
+
+  /**
+   * {@inheritdoc}
    */
-  public function testIndex() {
-    $controller = new EntryPoint(
-      \Drupal::service('jsonapi.resource_type.repository'),
+  public function setUp() {
+    parent::setUp();
+    $resource_repository = $this->prophesize(ResourceTypeRepositoryInterface::class);
+    $resource_repository->all()->willReturn([
+      new ResourceType('user', 'user', NULL),
+      new ResourceType('node_type', 'node_type', NULL),
+      new ResourceType('menu', 'menu', NULL, TRUE),
+    ]);
+    $this->entryPoint = new EntryPoint(
+      $resource_repository->reveal(),
       \Drupal::service('renderer'),
       new CacheableJsonResponse()
     );
-    $processed_response = $controller->index();
-    $this->assertEquals(
+  }
+
+  /**
+   * @covers ::index
+   *
+   * @param string $path
+   *   The regular expression which should validate the link.
+   * @param string $link
+   *   The link key to test.
+   *
+   * @dataProvider indexProvider
+   */
+  public function testIndex($path, $link) {
+    $data = json_decode($this->entryPoint->index()->getContent(), TRUE);
+    $this->assertRegExp($path, $data['links'][$link]);
+  }
+
+  /**
+   * Provides test cases to test entry point route generation.
+   */
+  public function indexProvider() {
+    return [
+      'root' => ['path' => '/.*\/jsonapi/', 'link' => 'self'],
+      'user' => ['path' => '/.*\/jsonapi\/user\/user/', 'link' => 'user--user'],
+      'node_type' => ['path' => '/.*\/jsonapi\/node_type\/node_type/', 'link' => 'node_type--node_type'],
+    ];
+  }
+
+  /**
+   * Ensures that internal resources are not present in the entry point.
+   */
+  public function testInternalResource() {
+    $data = json_decode($this->entryPoint->index()->getContent(), TRUE);
+    $this->assertArrayNotHasKey('menu--menu', $data['links']);
+  }
+
+  /**
+   * Ensures that the site name cache context was added.
+   */
+  public function testCacheContext() {
+    $this->assertArraySubset(
       ['url.site'],
-      $processed_response->getCacheableMetadata()->getCacheContexts()
+      $this->entryPoint->index()->getCacheableMetadata()->getCacheContexts()
     );
-    $data = json_decode($processed_response->getContent(), TRUE);
-    $links = $data['links'];
-    $this->assertRegExp('/.*\/jsonapi/', $links['self']);
-    $this->assertRegExp('/.*\/jsonapi\/user\/user/', $links['user--user']);
-    $this->assertRegExp('/.*\/jsonapi\/node_type\/node_type/', $links['node_type--node_type']);
   }
 
 }
diff --git a/tests/src/Kernel/EntityToJsonApiTest.php b/tests/src/Kernel/EntityToJsonApiTest.php
index 6bc0260..82ba6b9 100644
--- a/tests/src/Kernel/EntityToJsonApiTest.php
+++ b/tests/src/Kernel/EntityToJsonApiTest.php
@@ -139,7 +139,7 @@ class EntityToJsonApiTest extends JsonapiKernelTestBase {
 
     $link_manager = $this->prophesize(LinkManager::class);
     $link_manager
-      ->getEntityLink(Argument::any(), Argument::any(), Argument::type('array'), Argument::type('string'))
+      ->getEntityLink(Argument::any(), Argument::any(), Argument::type('array'), Argument::type('string'), Argument::cetera())
       ->willReturn('dummy_entity_link');
     $link_manager
       ->getRequestLink(Argument::any())
diff --git a/tests/src/Kernel/Normalizer/JsonApiDocumentTopLevelNormalizerTest.php b/tests/src/Kernel/Normalizer/JsonApiDocumentTopLevelNormalizerTest.php
index ce06be1..c4e25ec 100644
--- a/tests/src/Kernel/Normalizer/JsonApiDocumentTopLevelNormalizerTest.php
+++ b/tests/src/Kernel/Normalizer/JsonApiDocumentTopLevelNormalizerTest.php
@@ -155,7 +155,7 @@ class JsonApiDocumentTopLevelNormalizerTest extends JsonapiKernelTestBase {
 
     $link_manager = $this->prophesize(LinkManager::class);
     $link_manager
-      ->getEntityLink(Argument::any(), Argument::any(), Argument::type('array'), Argument::type('string'))
+      ->getEntityLink(Argument::any(), Argument::any(), Argument::type('array'), Argument::type('string'), Argument::cetera())
       ->willReturn('dummy_entity_link');
     $link_manager
       ->getRequestLink(Argument::any())
diff --git a/tests/src/Kernel/ResourceType/RelatedResourceTypesTest.php b/tests/src/Kernel/ResourceType/RelatedResourceTypesTest.php
new file mode 100644
index 0000000..d77034d
--- /dev/null
+++ b/tests/src/Kernel/ResourceType/RelatedResourceTypesTest.php
@@ -0,0 +1,182 @@
+<?php
+
+namespace Drupal\Tests\jsonapi\Kernel\ResourceType;
+
+use Drupal\Tests\jsonapi\Kernel\JsonapiKernelTestBase;
+use Drupal\node\Entity\NodeType;
+
+/**
+ * @coversDefaultClass \Drupal\jsonapi\ResourceType\ResourceType
+ * @coversClass \Drupal\jsonapi\ResourceType\ResourceTypeRepository
+ * @group jsonapi
+ *
+ * @internal
+ */
+class RelatedResourceTypesTest extends JsonapiKernelTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static $modules = [
+    'node',
+    'jsonapi',
+    'serialization',
+    'system',
+    'user',
+    'field',
+  ];
+
+  /**
+   * The JSON API resource type repository under test.
+   *
+   * @var \Drupal\jsonapi\ResourceType\ResourceTypeRepository
+   */
+  protected $resourceTypeRepository;
+
+  /**
+   * The JSON API resource type for `node--foo`.
+   *
+   * @var \Drupal\jsonapi\ResourceType\ResourceType
+   */
+  protected $fooType;
+
+  /**
+   * The JSON API resource type for `node--bar`.
+   *
+   * @var \Drupal\jsonapi\ResourceType\ResourceType
+   */
+  protected $barType;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+    // Add the entity schemas.
+    $this->installEntitySchema('node');
+    $this->installEntitySchema('user');
+
+    // Add the additional table schemas.
+    $this->installSchema('system', ['sequences']);
+    $this->installSchema('node', ['node_access']);
+    $this->installSchema('user', ['users_data']);
+
+    NodeType::create([
+      'type' => 'foo',
+    ])->save();
+
+    NodeType::create([
+      'type' => 'bar',
+    ])->save();
+
+    $this->createEntityReferenceField(
+      'node',
+      'foo',
+      'field_ref_bar',
+      'Bar Reference',
+      'node',
+      'default',
+      ['target_bundles' => ['bar']]
+    );
+
+    $this->createEntityReferenceField(
+      'node',
+      'foo',
+      'field_ref_foo',
+      'Foo Reference',
+      'node',
+      'default',
+      // Important to test self-referencing resource types.
+      ['target_bundles' => ['foo']]
+    );
+
+    $this->createEntityReferenceField(
+      'node',
+      'foo',
+      'field_ref_any',
+      'Any Bundle Reference',
+      'node',
+      'default',
+      // This should result in a reference to any bundle.
+      ['target_bundles' => NULL]
+    );
+
+    $this->resourceTypeRepository = $this->container->get('jsonapi.resource_type.repository');
+  }
+
+  /**
+   * @covers ::getRelatableResourceTypes
+   * @dataProvider getRelatableResourceTypesProvider
+   */
+  public function testGetRelatableResourceTypes($resource_type_name, $relatable_type_names) {
+    // We're only testing the fields that we set up.
+    $test_fields = [
+      'field_ref_foo',
+      'field_ref_bar',
+      'field_ref_any',
+    ];
+
+    $resource_type = $this->resourceTypeRepository->getByTypeName($resource_type_name);
+
+    // This extracts just the relationship fields under test.
+    $subjects = array_intersect_key(
+      $resource_type->getRelatableResourceTypes(),
+      array_flip($test_fields)
+    );
+
+    // Map the related resource type to their type name so we can just compare
+    // the type names rather that the whole object.
+    foreach ($test_fields as $field_name) {
+      if (isset($subjects[$field_name])) {
+        $subjects[$field_name] = array_map(function ($resource_type) {
+          return $resource_type->getTypeName();
+        }, $subjects[$field_name]);
+      }
+    }
+
+    $this->assertArraySubset($relatable_type_names, $subjects);
+  }
+
+  /**
+   * @covers ::getRelatableResourceTypes
+   * @dataProvider getRelatableResourceTypesProvider
+   */
+  public function getRelatableResourceTypesProvider() {
+    return [
+      [
+        'node--foo',
+        [
+          'field_ref_foo' => ['node--foo'],
+          'field_ref_bar' => ['node--bar'],
+          'field_ref_any' => ['node--foo', 'node--bar'],
+        ],
+      ],
+      ['node--bar', []],
+    ];
+  }
+
+  /**
+   * @covers ::getRelatableResourceTypesByField
+   * @dataProvider getRelatableResourceTypesByFieldProvider
+   */
+  public function testGetRelatableResourceTypesByField($entity_type_id, $bundle, $field) {
+    $resource_type = $this->resourceTypeRepository->get($entity_type_id, $bundle);
+    $relatable_types = $resource_type->getRelatableResourceTypes();
+    $this->assertSame(
+      $relatable_types[$field],
+      $resource_type->getRelatableResourceTypesByField($field)
+    );
+  }
+
+  /**
+   * Provides cases to test getRelatableTypesByField.
+   */
+  public function getRelatableResourceTypesByFieldProvider() {
+    return [
+      ['node', 'foo', 'field_ref_foo'],
+      ['node', 'foo', 'field_ref_bar'],
+      ['node', 'foo', 'field_ref_any'],
+    ];
+  }
+
+}
diff --git a/tests/src/Unit/Normalizer/JsonApiDocumentTopLevelNormalizerTest.php b/tests/src/Unit/Normalizer/JsonApiDocumentTopLevelNormalizerTest.php
index 3013221..4f49fcf 100644
--- a/tests/src/Unit/Normalizer/JsonApiDocumentTopLevelNormalizerTest.php
+++ b/tests/src/Unit/Normalizer/JsonApiDocumentTopLevelNormalizerTest.php
@@ -42,14 +42,9 @@ class JsonApiDocumentTopLevelNormalizerTest extends UnitTestCase {
     $resource_type_repository = $this->prophesize(ResourceTypeRepository::class);
     $field_resolver = $this->prophesize(FieldResolver::class);
 
-    $resource_type = $this->prophesize(ResourceType::class);
-    $resource_type
-      ->getEntityTypeId()
-      ->willReturn('node');
-
     $resource_type_repository
       ->getByTypeName(Argument::any())
-      ->willReturn($resource_type->reveal());
+      ->willReturn(new ResourceType('node', 'article', NULL));
 
     $entity_storage = $this->prophesize(EntityStorageInterface::class);
     $self = $this;
diff --git a/tests/src/Unit/Normalizer/Value/RelationshipNormalizerValueTest.php b/tests/src/Unit/Normalizer/Value/RelationshipNormalizerValueTest.php
index e66e9c3..3f7c2b2 100644
--- a/tests/src/Unit/Normalizer/Value/RelationshipNormalizerValueTest.php
+++ b/tests/src/Unit/Normalizer/Value/RelationshipNormalizerValueTest.php
@@ -25,7 +25,7 @@ class RelationshipNormalizerValueTest extends UnitTestCase {
   public function testRasterizeValue($values, $cardinality, $expected) {
     $link_manager = $this->prophesize(LinkManager::class);
     $link_manager
-      ->getEntityLink(Argument::any(), Argument::any(), Argument::type('array'), Argument::type('string'))
+      ->getEntityLink(Argument::any(), Argument::any(), Argument::type('array'), Argument::type('string'), Argument::type('string'))
       ->willReturn('dummy_entity_link');
     $object = new RelationshipNormalizerValue($values, $cardinality, [
       'link_manager' => $link_manager->reveal(),
diff --git a/tests/src/Unit/Routing/RoutesTest.php b/tests/src/Unit/Routing/RoutesTest.php
index cb1285d..c8fd07c 100644
--- a/tests/src/Unit/Routing/RoutesTest.php
+++ b/tests/src/Unit/Routing/RoutesTest.php
@@ -31,10 +31,17 @@ class RoutesTest extends UnitTestCase {
    */
   protected function setUp() {
     parent::setUp();
+    $type_1 = new ResourceType('entity_type_1', 'bundle_1_1', EntityInterface::class);
+    $type_2 = new ResourceType('entity_type_2', 'bundle_2_1', EntityInterface::class, TRUE);
+    $relatable_resource_types = [
+      'external' => [$type_1],
+      'internal' => [$type_2],
+      'both' => [$type_1, $type_2],
+    ];
+    $type_1->setRelatableResourceTypes($relatable_resource_types);
+    $type_2->setRelatableResourceTypes($relatable_resource_types);
     $resource_type_repository = $this->prophesize(ResourceTypeRepository::class);
-    $resource_type_repository->all()->willReturn([
-      new ResourceType('entity_type_1', 'bundle_1_1', EntityInterface::class),
-    ]);
+    $resource_type_repository->all()->willReturn([$type_1, $type_2]);
     $container = $this->prophesize(ContainerInterface::class);
     $container->get('jsonapi.resource_type.repository')->willReturn($resource_type_repository->reveal());
     $auth_collector = $this->prophesize(AuthenticationCollectorInterface::class);
@@ -54,9 +61,6 @@ class RoutesTest extends UnitTestCase {
     // Get the route collection and start making assertions.
     $routes = $this->routes['ok']->routes();
 
-    // Make sure that there are 4 routes for each resource.
-    $this->assertEquals(4, $routes->count());
-
     $iterator = $routes->getIterator();
     // Check the collection route.
     /** @var \Symfony\Component\Routing\Route $route */
@@ -99,8 +103,8 @@ class RoutesTest extends UnitTestCase {
 
     // Check the related route.
     /** @var \Symfony\Component\Routing\Route $route */
-    $route = $iterator->offsetGet('jsonapi.entity_type_1--bundle_1_1.related');
-    $this->assertSame('/jsonapi/entity_type_1/bundle_1_1/{entity_type_1}/{related}', $route->getPath());
+    $route = $iterator->offsetGet('jsonapi.entity_type_1--bundle_1_1.related.external');
+    $this->assertSame('/jsonapi/entity_type_1/bundle_1_1/{entity_type_1}/external', $route->getPath());
     $this->assertSame('entity_type_1', $route->getRequirement('_entity_type'));
     $this->assertSame('bundle_1_1', $route->getRequirement('_bundle'));
     $this->assertEquals(['GET'], $route->getMethods());
@@ -118,8 +122,8 @@ class RoutesTest extends UnitTestCase {
 
     // Check the relationships route.
     /** @var \Symfony\Component\Routing\Route $route */
-    $route = $iterator->offsetGet('jsonapi.entity_type_1--bundle_1_1.relationship');
-    $this->assertSame('/jsonapi/entity_type_1/bundle_1_1/{entity_type_1}/relationships/{related}', $route->getPath());
+    $route = $iterator->offsetGet('jsonapi.entity_type_1--bundle_1_1.relationship.internal');
+    $this->assertSame('/jsonapi/entity_type_1/bundle_1_1/{entity_type_1}/relationships/internal', $route->getPath());
     $this->assertSame('entity_type_1', $route->getRequirement('_entity_type'));
     $this->assertSame('bundle_1_1', $route->getRequirement('_bundle'));
     $this->assertEquals(['GET', 'POST', 'PATCH', 'DELETE'], $route->getMethods());
@@ -129,4 +133,57 @@ class RoutesTest extends UnitTestCase {
     $this->assertSame('Drupal\Core\Field\EntityReferenceFieldItemList', $route->getOption('serialization_class'));
   }
 
+  /**
+   * Ensures that the expected routes are created or not created.
+   *
+   * @dataProvider expectedRoutes
+   */
+  public function testRoutes($route) {
+    $this->assertArrayHasKey($route, $this->routes['ok']->routes()->all());
+  }
+
+  /**
+   * Lists routes which should have been created.
+   */
+  public function expectedRoutes() {
+    return [
+      ['jsonapi.entity_type_1--bundle_1_1.individual'],
+      ['jsonapi.entity_type_1--bundle_1_1.collection'],
+      ['jsonapi.entity_type_1--bundle_1_1.related.external'],
+      ['jsonapi.entity_type_1--bundle_1_1.related.both'],
+      ['jsonapi.entity_type_1--bundle_1_1.relationship.internal'],
+      ['jsonapi.entity_type_1--bundle_1_1.relationship.external'],
+      ['jsonapi.entity_type_1--bundle_1_1.relationship.both'],
+    ];
+  }
+
+  /**
+   * Ensures that no routes are created for internal resources.
+   *
+   * @dataProvider notExpectedRoutes
+   */
+  public function testInternalRoutes($route) {
+    $this->assertArrayNotHasKey($route, $this->routes['ok']->routes()->all());
+  }
+
+  /**
+   * Lists routes which should have been created.
+   */
+  public function notExpectedRoutes() {
+    return [
+      ['jsonapi.entity_type_1--bundle_1_1.related.none'],
+      ['jsonapi.entity_type_1--bundle_1_1.related.internal'],
+      ['jsonapi.entity_type_1--bundle_1_1.relationship.none'],
+
+      ['jsonapi.entity_type_2--bundle_2_1.individual'],
+      ['jsonapi.entity_type_2--bundle_2_1.collection'],
+      ['jsonapi.entity_type_2--bundle_2_1.related.both'],
+      ['jsonapi.entity_type_2--bundle_2_1.related.external'],
+      ['jsonapi.entity_type_2--bundle_2_1.relationship.none'],
+      ['jsonapi.entity_type_2--bundle_2_1.relationship.internal'],
+      ['jsonapi.entity_type_2--bundle_2_1.relationship.external'],
+      ['jsonapi.entity_type_2--bundle_2_1.relationship.both'],
+    ];
+  }
+
 }
