diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 76bc81e728aa85e1dd79d465ef88f715eb53a3c6..19ad8ddc359c54eeb7721d7c71c7859bb2f118ed 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -20,6 +20,7 @@ variables:
   OPT_IN_TEST_PREVIOUS_MINOR: 1
   OPT_IN_TEST_NEXT_MINOR: 1
   OPT_IN_TEST_MAX_PHP: 1
+  _PHPUNIT_CONCURRENT: 1
 
 phpstan (custom):
   extends: phpstan
diff --git a/composer.json b/composer.json
index 3c16f405edfa5b986e3770a59249789d43923712..064b79dae36291a46073978a112a3cb939de68e6 100644
--- a/composer.json
+++ b/composer.json
@@ -10,14 +10,14 @@
     "webonyx/graphql-php": "^15.19.1"
   },
   "require-dev": {
-    "drupal/coder": "8.3.26",
+    "drupal/coder": "8.3.28",
     "slevomat/coding-standard": "^8.16",
     "drupal/redirect": "^1.0",
-    "phpstan/phpstan": "^1.11.2",
-    "mglaman/phpstan-drupal": "^1.1.2",
-    "phpstan/phpstan-deprecation-rules": "^1.0.0",
-    "jangregor/phpstan-prophecy": "^1.0.0",
-    "phpstan/phpstan-phpunit": "^1.0.0",
+    "phpstan/phpstan": "^2.1.11 || ^1",
+    "mglaman/phpstan-drupal": "^2.0.2 || ^1",
+    "phpstan/phpstan-deprecation-rules": "^2 || ^1",
+    "jangregor/phpstan-prophecy": "^2 || ^1",
+    "phpstan/phpstan-phpunit": "^2 || ^1",
     "phpstan/extension-installer": "^1.0"
   },
   "minimum-stability": "dev"
diff --git a/examples/graphql_composable/graphql_composable.info.yml b/examples/graphql_composable/graphql_composable.info.yml
index 08add43f5203066ab455e17b9e614cad654b5453..a8bf56c5c8347d0f52b97d20ac2bb363daafd844 100644
--- a/examples/graphql_composable/graphql_composable.info.yml
+++ b/examples/graphql_composable/graphql_composable.info.yml
@@ -5,4 +5,4 @@ package: GraphQL
 dependencies:
   - graphql:graphql
   - node:node
-core_version_requirement: ^10.2 || ^11
+core_version_requirement: ^10.4 || ^11
diff --git a/examples/graphql_composable/src/Plugin/GraphQL/Schema/ComposableSchemaExample.php b/examples/graphql_composable/src/Plugin/GraphQL/Schema/ComposableSchemaExample.php
index 5df91ca2056a1e7d19ce56bc904eaa442c8a5861..9e37162e8ff688c4747e0079b0bd95407007e783 100644
--- a/examples/graphql_composable/src/Plugin/GraphQL/Schema/ComposableSchemaExample.php
+++ b/examples/graphql_composable/src/Plugin/GraphQL/Schema/ComposableSchemaExample.php
@@ -7,6 +7,8 @@ namespace Drupal\graphql_composable\Plugin\GraphQL\Schema;
 use Drupal\graphql\Plugin\GraphQL\Schema\ComposableSchema;
 
 /**
+ * Example of a composable schema.
+ *
  * @Schema(
  *   id = "composable",
  *   name = "Composable Example schema",
diff --git a/examples/graphql_composable/src/Plugin/GraphQL/SchemaExtension/ComposableSchemaExampleExtension.php b/examples/graphql_composable/src/Plugin/GraphQL/SchemaExtension/ComposableSchemaExampleExtension.php
index f16d4ab9b2a5fb36b335d8d4ceb3272c2d9a7bba..730ab8f30d04c439f2b2690a00792dc88110afbf 100644
--- a/examples/graphql_composable/src/Plugin/GraphQL/SchemaExtension/ComposableSchemaExampleExtension.php
+++ b/examples/graphql_composable/src/Plugin/GraphQL/SchemaExtension/ComposableSchemaExampleExtension.php
@@ -11,6 +11,8 @@ use Drupal\graphql\Plugin\GraphQL\SchemaExtension\SdlSchemaExtensionPluginBase;
 use Drupal\graphql_composable\GraphQL\Response\ArticleResponse;
 
 /**
+ * Example schema plugin for extending the composable schema.
+ *
  * @SchemaExtension(
  *   id = "composable_extension",
  *   name = "Composable Example extension",
diff --git a/examples/graphql_example/graphql_examples.info.yml b/examples/graphql_example/graphql_examples.info.yml
index 4f03a1abe8a47e3eb6bf95d71518946e85b2abaf..ef277a30692444e23273a5b78a7310ed1f15f5fb 100644
--- a/examples/graphql_example/graphql_examples.info.yml
+++ b/examples/graphql_example/graphql_examples.info.yml
@@ -5,4 +5,4 @@ package: GraphQL
 dependencies:
   - graphql:graphql
   - node:node
-core_version_requirement: ^10.2 || ^11
+core_version_requirement: ^10.4 || ^11
diff --git a/examples/graphql_example/src/Plugin/GraphQL/DataProducer/QueryArticles.php b/examples/graphql_example/src/Plugin/GraphQL/DataProducer/QueryArticles.php
index 8174e218145ffb1d41b31c6fd79ca349d4eb080d..7a52afcfb0a65f85523cdb58b33f579e62ff9778 100644
--- a/examples/graphql_example/src/Plugin/GraphQL/DataProducer/QueryArticles.php
+++ b/examples/graphql_example/src/Plugin/GraphQL/DataProducer/QueryArticles.php
@@ -15,6 +15,8 @@ use GraphQL\Error\UserError;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
+ * Example data producer that loads a list of articles.
+ *
  * @DataProducer(
  *   id = "query_articles",
  *   name = @Translation("Load articles"),
@@ -71,9 +73,7 @@ class QueryArticles extends DataProducerPluginBase implements ContainerFactoryPl
   }
 
   /**
-   *
-   * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
-   * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
+   * Resolves the query by preparing an entity query for executing later.
    */
   public function resolve(int $offset, int $limit, RefinableCacheableDependencyInterface $metadata): QueryConnection {
     if ($limit > static::MAX_LIMIT) {
diff --git a/examples/graphql_example/src/Plugin/GraphQL/Schema/ExampleSchema.php b/examples/graphql_example/src/Plugin/GraphQL/Schema/ExampleSchema.php
index 8012c5528b05807ef18f3ecbf349e13987d53f11..c5d327547939efedfc2ec10ec8e8185c5f5eddc5 100644
--- a/examples/graphql_example/src/Plugin/GraphQL/Schema/ExampleSchema.php
+++ b/examples/graphql_example/src/Plugin/GraphQL/Schema/ExampleSchema.php
@@ -11,6 +11,8 @@ use Drupal\graphql\Plugin\GraphQL\Schema\SdlSchemaPluginBase;
 use Drupal\graphql_examples\Wrappers\QueryConnection;
 
 /**
+ * Example schema plugin that maps article data.
+ *
  * @Schema(
  *   id = "example",
  *   name = "Example schema"
diff --git a/examples/graphql_example/src/Plugin/GraphQL/SchemaExtension/ExampleSchemaExtension.php b/examples/graphql_example/src/Plugin/GraphQL/SchemaExtension/ExampleSchemaExtension.php
index 80f35743d91eeb84b55b22f17e736891dfe8baef..21c35281674cdcd5759d0c0c740ddbce05170c25 100644
--- a/examples/graphql_example/src/Plugin/GraphQL/SchemaExtension/ExampleSchemaExtension.php
+++ b/examples/graphql_example/src/Plugin/GraphQL/SchemaExtension/ExampleSchemaExtension.php
@@ -9,6 +9,8 @@ use Drupal\graphql\GraphQL\ResolverRegistryInterface;
 use Drupal\graphql\Plugin\GraphQL\SchemaExtension\SdlSchemaExtensionPluginBase;
 
 /**
+ * Example schema extension that adds to the mapping.
+ *
  * @SchemaExtension(
  *   id = "example_extension",
  *   name = "Example extension",
diff --git a/graphql.info.yml b/graphql.info.yml
index e97d14ff6e9f35716804644ea2d4b86322835f6b..e07fdd8b4eb731ba41c37ec735a6868295a585d2 100644
--- a/graphql.info.yml
+++ b/graphql.info.yml
@@ -3,6 +3,6 @@ type: module
 description: 'Base module for integrating GraphQL with Drupal.'
 package: GraphQL
 configure: entity.graphql_server.collection
-core_version_requirement: ^10.3 || ^11
+core_version_requirement: ^10.4 || ^11
 dependencies:
   - typed_data:typed_data
diff --git a/phpcs.xml.dist b/phpcs.xml.dist
index 9309f733a5cf357d878feb971ac02565c3cc71fe..22ac87315ba442e835ce207c5a5a12287787ace1 100644
--- a/phpcs.xml.dist
+++ b/phpcs.xml.dist
@@ -34,41 +34,13 @@
     <exclude-pattern>src/GraphQL/Buffers/BufferBase.php</exclude-pattern>
     <exclude-pattern>src/GraphQL/Execution/FieldContext.php</exclude-pattern>
     <exclude-pattern>src/GraphQL/Execution/ResolveContext.php</exclude-pattern>
+    <exclude-pattern>src/GraphQL/Utility/FileUpload.php</exclude-pattern>
     <exclude-pattern>src/Plugin/GraphQL/DataProducer/Utility/Seek.php</exclude-pattern>
     <exclude-pattern>src/SubRequestResponse.php</exclude-pattern>
     <exclude-pattern>tests/src/Traits/QueryResultAssertionTrait.php</exclude-pattern>
     <exclude-pattern>tests/src/Traits/MockingTrait.php</exclude-pattern>
   </rule>
 
-  <rule ref="Drupal.Commenting.DocComment.MissingShort">
-    <exclude-pattern>src/Plugin/GraphQL/Schema/SdlSchemaPluginBase.php</exclude-pattern>
-    <exclude-pattern>src/Plugin/GraphQL/Schema/ComposableSchema.php</exclude-pattern>
-    <exclude-pattern>src/Plugin/DataProducerPluginManager.php</exclude-pattern>
-    <exclude-pattern>src/Plugin/PersistedQueryPluginInterface.php</exclude-pattern>
-    <exclude-pattern>src/Plugin/DataProducerPluginCachingInterface.php</exclude-pattern>
-    <exclude-pattern>src/Controller/RequestController.php</exclude-pattern>
-    <exclude-pattern>examples/graphql_example/src/Wrappers/QueryConnection.php</exclude-pattern>
-    <exclude-pattern>examples/graphql_example/src/Plugin/GraphQL/DataProducer/QueryArticles.php</exclude-pattern>
-    <exclude-pattern>examples/graphql_example/src/Plugin/GraphQL/Schema/ExampleSchema.php</exclude-pattern>
-    <exclude-pattern>examples/graphql_example/src/Plugin/GraphQL/SchemaExtension/ExampleSchemaExtension.php</exclude-pattern>
-    <exclude-pattern>examples/graphql_composable/src/Plugin/GraphQL/Schema/ComposableSchemaExample.php</exclude-pattern>
-    <exclude-pattern>examples/graphql_composable/src/Plugin/GraphQL/SchemaExtension/ComposableSchemaExampleExtension.php</exclude-pattern>
-    <exclude-pattern>tests/src/Traits/MockingTrait.php</exclude-pattern>
-    <exclude-pattern>tests/src/Traits/QueryResultAssertionTrait.php</exclude-pattern>
-    <exclude-pattern>tests/src/Traits/DataProducerExecutionTrait.php</exclude-pattern>
-    <exclude-pattern>tests/src/Kernel/ResolverBuilderTest.php</exclude-pattern>
-    <exclude-pattern>tests/src/Kernel/EntityBufferTest.php</exclude-pattern>
-    <exclude-pattern>tests/src/Kernel/DataProducer/MenuTest.php</exclude-pattern>
-    <exclude-pattern>tests/src/Kernel/DataProducer/EntityMultipleTest.php</exclude-pattern>
-    <exclude-pattern>tests/src/Kernel/DataProducer/EntityTest.php</exclude-pattern>
-    <exclude-pattern>tests/src/Kernel/EntityUuidBufferTest.php</exclude-pattern>
-    <exclude-pattern>tests/src/Kernel/Framework/PersistedQueriesTest.php</exclude-pattern>
-    <exclude-pattern>tests/src/Kernel/GraphQLTestBase.php</exclude-pattern>
-    <exclude-pattern>tests/modules/graphql_persisted_queries_test/src/Plugin/GraphQL/PersistedQuery/PersistedQueryPluginThree.php</exclude-pattern>
-    <exclude-pattern>tests/modules/graphql_persisted_queries_test/src/Plugin/GraphQL/PersistedQuery/PersistedQueryPluginOne.php</exclude-pattern>
-    <exclude-pattern>tests/modules/graphql_persisted_queries_test/src/Plugin/GraphQL/PersistedQuery/PersistedQueryPluginTwo.php</exclude-pattern>
-  </rule>
-
   <rule ref="Drupal.Commenting.FunctionComment.MissingParamComment">
     <exclude-pattern>src/PermissionProvider.php</exclude-pattern>
     <exclude-pattern>src/Config/LanguageConfigOverride.php</exclude-pattern>
diff --git a/src/Entity/Server.php b/src/Entity/Server.php
index 352f1ea68a3a0e791d45c54652706b9dca2c25c7..e13dddfda90151d2fda557285edbb62e375e80f8 100644
--- a/src/Entity/Server.php
+++ b/src/Entity/Server.php
@@ -148,13 +148,6 @@ class Server extends ConfigEntityBase implements ServerInterface {
    */
   protected ?array $persisted_query_instances = NULL;
 
-  /**
-   * The sorted persisted query plugin instances available on this server.
-   *
-   * @var array|null
-   */
-  protected ?array $sorted_persisted_query_instances = NULL;
-
   /**
    * {@inheritdoc}
    */
@@ -302,9 +295,7 @@ class Server extends ConfigEntityBase implements ServerInterface {
     return function (OperationParams $params, DocumentNode $document, $type) use ($schema, $config) {
       $context = new ResolveContext($this, $params, $document, $type, $config);
       $context->addCacheTags(['graphql_response']);
-      if ($this instanceof CacheableDependencyInterface) {
-        $context->addCacheableDependency($this);
-      }
+      $context->addCacheableDependency($this);
 
       if ($schema instanceof CacheableDependencyInterface) {
         $context->addCacheableDependency($schema);
@@ -371,7 +362,6 @@ class Server extends ConfigEntityBase implements ServerInterface {
    */
   public function removeAllPersistedQueryInstances(): void {
     $this->persisted_query_instances = NULL;
-    $this->sorted_persisted_query_instances = NULL;
   }
 
   /**
@@ -381,6 +371,7 @@ class Server extends ConfigEntityBase implements ServerInterface {
     if (!is_null($this->persisted_query_instances)) {
       return $this->persisted_query_instances;
     }
+    $this->persisted_query_instances = [];
 
     /** @var \Drupal\graphql\Plugin\PersistedQueryPluginManager $plugin_manager */
     $plugin_manager = \Drupal::service('plugin.manager.graphql.persisted_query');
@@ -392,24 +383,11 @@ class Server extends ConfigEntityBase implements ServerInterface {
         $this->persisted_query_instances[$id] = $plugin_manager->createInstance($id, $configuration);
       }
     }
+    uasort($this->persisted_query_instances, function ($a, $b) {
+      return $a->getWeight() <= $b->getWeight() ? -1 : 1;
+    });
 
-    return $this->persisted_query_instances ?? [];
-  }
-
-  /**
-   * {@inheritDoc}
-   */
-  public function getSortedPersistedQueryInstances(): array {
-    if (!is_null($this->sorted_persisted_query_instances)) {
-      return $this->sorted_persisted_query_instances;
-    }
-    $this->sorted_persisted_query_instances = $this->getPersistedQueryInstances();
-    if (!empty($this->sorted_persisted_query_instances)) {
-      uasort($this->sorted_persisted_query_instances, function ($a, $b) {
-        return $a->getWeight() <= $b->getWeight() ? -1 : 1;
-      });
-    }
-    return $this->sorted_persisted_query_instances;
+    return $this->persisted_query_instances;
   }
 
   /**
@@ -420,7 +398,7 @@ class Server extends ConfigEntityBase implements ServerInterface {
    */
   protected function getPersistedQueryLoader(): callable {
     return function ($id, OperationParams $params) {
-      $sortedPersistedQueryInstances = $this->getSortedPersistedQueryInstances();
+      $sortedPersistedQueryInstances = $this->getPersistedQueryInstances();
       if (!empty($sortedPersistedQueryInstances)) {
         foreach ($sortedPersistedQueryInstances as $persistedQueryInstance) {
           $query = $persistedQueryInstance->getQuery($id, $params);
diff --git a/src/Entity/ServerInterface.php b/src/Entity/ServerInterface.php
index b618f889942b7643806baca52c5354d6d801b78e..6351911da9d3fc891e7d5ce9732f4920d8eb74ba 100644
--- a/src/Entity/ServerInterface.php
+++ b/src/Entity/ServerInterface.php
@@ -55,18 +55,11 @@ interface ServerInterface extends ConfigEntityInterface {
    */
   public function removeAllPersistedQueryInstances(): void;
 
-  /**
-   * Returns the current persisted queries set.
-   *
-   * @return array<\Drupal\graphql\Plugin\PersistedQueryPluginInterface>
-   */
-  public function getPersistedQueryInstances(): array;
-
   /**
    * Returns the current persisted queries set, sorted by the plugins weight.
    *
    * @return array<\Drupal\graphql\Plugin\PersistedQueryPluginInterface>
    */
-  public function getSortedPersistedQueryInstances(): array;
+  public function getPersistedQueryInstances(): array;
 
 }
diff --git a/src/GraphQL/Execution/Executor.php b/src/GraphQL/Execution/Executor.php
index 24fd5e02029e6b6284521cf42f3a1ac980bb385d..9c22ec11c899d3f2ac9102811ab3e7a07b36d1f8 100644
--- a/src/GraphQL/Execution/Executor.php
+++ b/src/GraphQL/Execution/Executor.php
@@ -13,7 +13,6 @@ use Drupal\Core\Utility\Error as ErrorUtil;
 use Drupal\graphql\Event\OperationEvent;
 use Drupal\graphql\GraphQL\Execution\ExecutionResult as CacheableExecutionResult;
 use Drupal\graphql\GraphQL\Utility\DocumentSerializer;
-use GraphQL\Error\ClientAware;
 use GraphQL\Executor\ExecutionResult;
 use GraphQL\Executor\ExecutorImplementation;
 use GraphQL\Executor\Promise\Promise;
@@ -200,7 +199,7 @@ class Executor implements ExecutorImplementation {
       // Don't log errors intended for clients, only log those that
       // a client would not be able to solve, they'd require work from
       // a server developer.
-      if ($error instanceof ClientAware && $error->isClientSafe()) {
+      if ($error->isClientSafe()) {
         continue;
       }
 
diff --git a/src/GraphQL/Resolver/Path.php b/src/GraphQL/Resolver/Path.php
deleted file mode 100644
index 827e5cfa34088b2caddd6518e1db141c22bfb19b..0000000000000000000000000000000000000000
--- a/src/GraphQL/Resolver/Path.php
+++ /dev/null
@@ -1,71 +0,0 @@
-<?php
-
-declare(strict_types=1);
-
-namespace Drupal\graphql\GraphQL\Resolver;
-
-use Drupal\Core\Cache\CacheableDependencyInterface;
-use Drupal\Core\Render\BubbleableMetadata;
-use Drupal\Core\TypedData\DataDefinition;
-use Drupal\Core\TypedData\DataDefinitionInterface;
-use Drupal\Core\TypedData\TypedDataTrait;
-use Drupal\graphql\GraphQL\Execution\FieldContext;
-use Drupal\graphql\GraphQL\Execution\ResolveContext;
-use Drupal\typed_data\DataFetcherTrait;
-use GraphQL\Type\Definition\ResolveInfo;
-
-/**
- * Resolves a property path.
- *
- * @todo Delete this resolver. This is a plugin already.
- */
-class Path implements ResolverInterface {
-
-  use TypedDataTrait;
-  use DataFetcherTrait;
-
-  /**
-   * Name of the context.
-   */
-  protected string|DataDefinitionInterface $type;
-
-  /**
-   * Source resolver.
-   */
-  protected mixed $path;
-
-  /**
-   * Resolver.
-   */
-  protected mixed $value;
-
-  /**
-   * Path constructor.
-   */
-  public function __construct(string $type, mixed $path, ?ResolverInterface $value = NULL) {
-    $this->type = $type;
-    $this->path = $path;
-    $this->value = $value;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function resolve(mixed $value, array $args, ResolveContext $context, ResolveInfo $info, FieldContext $field): mixed {
-    $value = $this->value ?? new ParentValue();
-    $value = $value->resolve($value, $args, $context, $info, $field);
-    $metadata = new BubbleableMetadata();
-
-    $type = $this->type instanceof DataDefinitionInterface ? $this->type : DataDefinition::create($this->type);
-    $data = $this->getTypedDataManager()->create($type, $value);
-    $output = $this->getDataFetcher()->fetchDataByPropertyPath($data, $this->path, $metadata)->getValue();
-
-    $context->addCacheableDependency($metadata);
-    if ($output instanceof CacheableDependencyInterface) {
-      $context->addCacheableDependency($output);
-    }
-
-    return $output;
-  }
-
-}
diff --git a/src/GraphQL/ResolverRegistry.php b/src/GraphQL/ResolverRegistry.php
index 0e0935f69fed9d328fa208f4beab56fbeb2cd736..f17832710fd8e2b3cf229e9e4db1e5150da5f811 100644
--- a/src/GraphQL/ResolverRegistry.php
+++ b/src/GraphQL/ResolverRegistry.php
@@ -22,7 +22,7 @@ class ResolverRegistry implements ResolverRegistryInterface {
    *
    * Contains a nested list of callables, keyed by type and field name.
    *
-   * @var array<callable>
+   * @var array<string, array<string, \Drupal\graphql\GraphQL\Resolver\ResolverInterface>>
    */
   protected array $fieldResolvers = [];
 
@@ -109,12 +109,7 @@ class ResolverRegistry implements ResolverRegistryInterface {
   }
 
   /**
-   * Return all field resolvers in the registry.
-   *
-   * @return array<callable>
-   *   A nested list of callables, keyed by type and field name.
-   *
-   * @todo This should be added to ResolverRegistryInterface in 5.0.0.
+   * {@inheritdoc}
    */
   public function getAllFieldResolvers(): array {
     return $this->fieldResolvers;
@@ -136,24 +131,7 @@ class ResolverRegistry implements ResolverRegistryInterface {
   }
 
   /**
-   * Get a field resolver for the type or any of the interfaces it implements.
-   *
-   * This allows common functionality (such as for Edge's or Connections) to be
-   * implemented for an interface and re-used on any concrete type that extends
-   * it.
-   *
-   * This should be used instead of `getFieldResolver` unless you're certain you
-   * want the resolver only for the specific type.
-   *
-   * @param \GraphQL\Type\Definition\Type $type
-   *   The type to find a resolver for.
-   * @param string $fieldName
-   *   The name of the field to find a resolver for.
-   *
-   * @return \Drupal\graphql\GraphQL\Resolver\ResolverInterface|null
-   *   The defined resolver for the field or NULL if none exists.
-   *
-   * @todo This should be added to ResolverRegistryInterface in 5.0.0.
+   * {@inheritdoc}
    */
   public function getFieldResolverWithInheritance(Type $type, string $fieldName): ?ResolverInterface {
     if ($resolver = $this->getFieldResolver($type->toString(), $fieldName)) {
diff --git a/src/GraphQL/ResolverRegistryInterface.php b/src/GraphQL/ResolverRegistryInterface.php
index f7f51ba5a32571f0918eff7b5f65e259a441ccf2..244349cf0ce2ce801ccd7fe28f0e9991ea3dfaa8 100644
--- a/src/GraphQL/ResolverRegistryInterface.php
+++ b/src/GraphQL/ResolverRegistryInterface.php
@@ -8,6 +8,7 @@ use Drupal\graphql\GraphQL\Execution\FieldContext;
 use Drupal\graphql\GraphQL\Execution\ResolveContext;
 use Drupal\graphql\GraphQL\Resolver\ResolverInterface;
 use GraphQL\Type\Definition\ResolveInfo;
+use GraphQL\Type\Definition\Type;
 
 /**
  * Defines a registry to resolve any field in the GraphQL schema tree.
@@ -29,11 +30,39 @@ interface ResolverRegistryInterface {
    */
   public function addFieldResolver(string $type, string $field, ResolverInterface $resolver): static;
 
+  /**
+   * Get a field resolver for the type or any of the interfaces it implements.
+   *
+   * This allows common functionality (such as for Edge's or Connections) to be
+   * implemented for an interface and re-used on any concrete type that extends
+   * it.
+   *
+   * This should be used instead of `getFieldResolver` unless you're certain you
+   * want the resolver only for the specific type.
+   *
+   * @param \GraphQL\Type\Definition\Type $type
+   *   The type to find a resolver for.
+   * @param string $fieldName
+   *   The name of the field to find a resolver for.
+   *
+   * @return \Drupal\graphql\GraphQL\Resolver\ResolverInterface|null
+   *   The defined resolver for the field or NULL if none exists.
+   */
+  public function getFieldResolverWithInheritance(Type $type, string $fieldName): ?ResolverInterface;
+
   /**
    * Return the field resolver for a given type and field name.
    */
   public function getFieldResolver(string $type, string $field): ?ResolverInterface;
 
+  /**
+   * Return all field resolvers in the registry.
+   *
+   * @return array<string, array<string, \Drupal\graphql\GraphQL\Resolver\ResolverInterface>>
+   *   A nested list of resolvers, keyed by type and field name.
+   */
+  public function getAllFieldResolvers(): array;
+
   /**
    * Add a type resolver.
    *
diff --git a/src/GraphQL/Utility/FileUpload.php b/src/GraphQL/Utility/FileUpload.php
index 0d058d81aab593ec70fa57adb2c96b6e94bf8d69..d4b07b4610f8d3bca878744dd28d0dbe4afabc02 100644
--- a/src/GraphQL/Utility/FileUpload.php
+++ b/src/GraphQL/Utility/FileUpload.php
@@ -13,6 +13,7 @@ use Drupal\Core\Config\ImmutableConfig;
 use Drupal\Core\Entity\EntityTypeManagerInterface;
 use Drupal\Core\File\Event\FileUploadSanitizeNameEvent;
 use Drupal\Core\File\Exception\FileException;
+use Drupal\Core\File\FileExists;
 use Drupal\Core\File\FileSystemInterface;
 use Drupal\Core\Image\ImageFactory;
 use Drupal\Core\Lock\LockBackendInterface;
@@ -235,10 +236,7 @@ class FileUpload {
     $file_uri = "{$destination}/{$prepared_filename}";
 
     $temp_file_path = $uploaded_file->getRealPath();
-
-    // Drupal 10.3 compatibility: use the deprecated constant for now.
-    // @phpstan-ignore-next-line as it is deprecated in D12.
-    $file_uri = $this->fileSystem->getDestinationFilename($file_uri, FileSystemInterface::EXISTS_RENAME);
+    $file_uri = $this->fileSystem->getDestinationFilename($file_uri, FileExists::Rename);
 
     // Lock based on the prepared file URI.
     $lock_id = $this->generateLockIdFromFileUri($file_uri);
@@ -286,9 +284,7 @@ class FileUpload {
       // FileSystemInterface::EXISTS_ERROR as the file location has already been
       // determined above in FileSystem::getDestinationFilename().
       try {
-        // Drupal 10.3 compatibility: use the deprecated constant for now.
-        // @phpstan-ignore-next-line as it is deprecated in D12.
-        $this->fileSystem->move($temp_file_path, $file_uri, FileSystemInterface::EXISTS_ERROR);
+        $this->fileSystem->move($temp_file_path, $file_uri, FileExists::Rename);
       }
       catch (FileException $e) {
         $response->addViolation($this->t('Unknown error while uploading the file "@file".', [
@@ -321,7 +317,7 @@ class FileUpload {
   /**
    * Validates uploaded files, saves them and returns a file upload response.
    *
-   * @param array<\Symfony\Component\HttpFoundation\File\UploadedFile> $uploaded_files
+   * @param array<\Symfony\Component\HttpFoundation\File\UploadedFile|mixed> $uploaded_files
    *   The file entities to upload.
    * @param array $settings
    *   File settings as specified in regular file field config. Contains keys:
diff --git a/src/GraphQL/Validator.php b/src/GraphQL/Validator.php
index e877c4d2f300cc03a9cb7161618e68c3a3cb63e2..f6910ba5703985a95e305b5a2d165fb3aefa8376 100644
--- a/src/GraphQL/Validator.php
+++ b/src/GraphQL/Validator.php
@@ -61,17 +61,6 @@ class Validator implements ValidatorInterface {
     $plugin = $this->getSchemaPlugin($server);
     $resolver_registry = $plugin->getResolverRegistry();
 
-    if (!method_exists($resolver_registry, "getFieldResolverWithInheritance")) {
-      $this->logger->warning(
-        "Could not get missing resolvers for @server_name as its registry class (@class) does not implement getFieldResolverWithInheritance.",
-        [
-          '@server_name' => $server->id(),
-          '@class' => get_class($resolver_registry),
-        ]
-      );
-      return [];
-    }
-
     try {
       $schema = $plugin->getSchema($resolver_registry);
     }
@@ -127,17 +116,6 @@ class Validator implements ValidatorInterface {
       return [];
     }
 
-    if (!method_exists($resolver_registry, "getAllFieldResolvers")) {
-      $this->logger->warning(
-        "Could not get orphaned resolvers for @server_name as its registry class (@class) does not implement getAllFieldResolvers.",
-        [
-          '@server_name' => $server->id(),
-          '@class' => get_class($resolver_registry),
-        ]
-      );
-      return [];
-    }
-
     $orphaned_resolvers = [];
     /**
      * @var string $type_name
diff --git a/src/Plugin/GraphQL/DataProducer/Entity/EntityQueryBase.php b/src/Plugin/GraphQL/DataProducer/Entity/EntityQueryBase.php
index 4c369b17075f6b6f3604d9e678474854a409ea48..3776227c6acec02ac693d09dc31900cbde7e4584 100644
--- a/src/Plugin/GraphQL/DataProducer/Entity/EntityQueryBase.php
+++ b/src/Plugin/GraphQL/DataProducer/Entity/EntityQueryBase.php
@@ -129,6 +129,8 @@ abstract class EntityQueryBase extends DataProducerPluginBase implements Contain
     }
 
     // Ensure that desired access checking is performed on the query.
+    // Not sure why PHPStan complains about this?
+    // @phpstan-ignore-next-line
     $query->accessCheck($access);
 
     // Filter entities only of given bundles, if desired.
diff --git a/src/Plugin/GraphQL/DataProducer/Menu/MenuLinks.php b/src/Plugin/GraphQL/DataProducer/Menu/MenuLinks.php
index a2dad2945280edb0023ea7bdc2cc358399f9d891..30573ca1eb34a5727d739652f2ad9366e340da8d 100644
--- a/src/Plugin/GraphQL/DataProducer/Menu/MenuLinks.php
+++ b/src/Plugin/GraphQL/DataProducer/Menu/MenuLinks.php
@@ -5,7 +5,6 @@ declare(strict_types=1);
 namespace Drupal\graphql\Plugin\GraphQL\DataProducer\Menu;
 
 use Drupal\Core\DependencyInjection\DependencySerializationTrait;
-use Drupal\Core\Menu\MenuLinkInterface;
 use Drupal\Core\Menu\MenuLinkTreeElement;
 use Drupal\Core\Menu\MenuLinkTreeInterface;
 use Drupal\Core\Menu\MenuTreeParameters;
@@ -88,7 +87,7 @@ class MenuLinks extends DataProducerPluginBase implements ContainerFactoryPlugin
 
     return array_filter($this->menuLinkTree->transform($tree, $manipulators), function (MenuLinkTreeElement $item) use ($context) {
       $context->addCacheableDependency($item->access);
-      return $item->link instanceof MenuLinkInterface && $item->link->isEnabled() && $item->access->isAllowed();
+      return $item->link->isEnabled() && $item->access->isAllowed();
     });
   }
 
diff --git a/src/Plugin/GraphQL/Schema/ComposableSchema.php b/src/Plugin/GraphQL/Schema/ComposableSchema.php
index 78eea5a4311b1e63c91567723b3933025c3173f0..81aec33c05f22bed9973233c6f334e639b2e82e1 100644
--- a/src/Plugin/GraphQL/Schema/ComposableSchema.php
+++ b/src/Plugin/GraphQL/Schema/ComposableSchema.php
@@ -12,6 +12,8 @@ use Drupal\Core\StringTranslation\StringTranslationTrait;
 use Drupal\graphql\GraphQL\ResolverRegistry;
 
 /**
+ * A schema that is composed of extensions, each adding to the schema.
+ *
  * @Schema(
  *   id = "composable",
  *   name = "Composable schema"
diff --git a/src/Plugin/GraphQL/Schema/SdlSchemaPluginBase.php b/src/Plugin/GraphQL/Schema/SdlSchemaPluginBase.php
index 2cfb22f0df3c1d3d5ec2d37b4cc1fd41668b16f9..3469d22de4e5f82adb2df24ca53eec90de0a59da 100644
--- a/src/Plugin/GraphQL/Schema/SdlSchemaPluginBase.php
+++ b/src/Plugin/GraphQL/Schema/SdlSchemaPluginBase.php
@@ -155,6 +155,8 @@ abstract class SdlSchemaPluginBase extends PluginBase implements SchemaPluginInt
   }
 
   /**
+   * Returns the list of schema extension plugins.
+   *
    * @return array<\Drupal\graphql\Plugin\SchemaExtensionPluginInterface>
    */
   protected function getExtensions(): array {
@@ -281,11 +283,8 @@ abstract class SdlSchemaPluginBase extends PluginBase implements SchemaPluginInt
     // Configurable schema plugins should be cached per server since the schema
     // depends on the server configuration.
     if ($this instanceof ConfigurableInterface) {
-      $server_id = $this->getConfiguration()['server_id'] ?? NULL;
-      if ($server_id) {
-        return "{$type}:{$this->getPluginId()}:{$server_id}";
-      }
-      @trigger_error('Retrieving a GraphQL schema from a configurable schema plugin instance without setting the "server_id" in the plugin configuration is deprecated in graphql:4.11.0 and will cause an InvalidPluginDefinitionException to be thrown from graphql:5.0.0. Ensure to always pass this configuration value so that the schema can be properly cached per server. See https://www.drupal.org/project/graphql/issues/3491736', E_USER_DEPRECATED);
+      $server_id = $this->getConfiguration()['server_id'];
+      return "{$type}:{$this->getPluginId()}:{$server_id}";
     }
     return "{$type}:{$this->getPluginId()}";
   }
diff --git a/tests/modules/graphql_persisted_queries_test/src/Plugin/GraphQL/PersistedQuery/PersistedQueryPluginOne.php b/tests/modules/graphql_persisted_queries_test/src/Plugin/GraphQL/PersistedQuery/PersistedQueryPluginOne.php
index 1cc813a7b05811a4a9e6f6dbf824c3318006f6f5..389133368d1b0d7d2bc2492150def0e95cfdedeb 100644
--- a/tests/modules/graphql_persisted_queries_test/src/Plugin/GraphQL/PersistedQuery/PersistedQueryPluginOne.php
+++ b/tests/modules/graphql_persisted_queries_test/src/Plugin/GraphQL/PersistedQuery/PersistedQueryPluginOne.php
@@ -8,14 +8,13 @@ use Drupal\graphql\PersistedQuery\PersistedQueryPluginBase;
 use GraphQL\Server\OperationParams;
 
 /**
+ * Test persisted plugin.
+ *
  * @PersistedQuery(
  *   id = "persisted_query_plugin_one",
  *   label = "Persisted Query One",
  *   description = "This is the first persisted query plugin"
  * )
- *
- * Class PersistedQueryPluginOne
- * @package Drupal\graphql_persisted_queries_test\Plugin\GraphQL\PersistedQuery
  */
 class PersistedQueryPluginOne extends PersistedQueryPluginBase {
 
diff --git a/tests/modules/graphql_persisted_queries_test/src/Plugin/GraphQL/PersistedQuery/PersistedQueryPluginThree.php b/tests/modules/graphql_persisted_queries_test/src/Plugin/GraphQL/PersistedQuery/PersistedQueryPluginThree.php
index d4f5a91eff3983d8ff6e8777af4d877bc7a6e601..aae70b1aba367ca842c77b9dff7b389731642d7b 100644
--- a/tests/modules/graphql_persisted_queries_test/src/Plugin/GraphQL/PersistedQuery/PersistedQueryPluginThree.php
+++ b/tests/modules/graphql_persisted_queries_test/src/Plugin/GraphQL/PersistedQuery/PersistedQueryPluginThree.php
@@ -8,14 +8,13 @@ use Drupal\graphql\PersistedQuery\PersistedQueryPluginBase;
 use GraphQL\Server\OperationParams;
 
 /**
+ * Test persisted plugin.
+ *
  * @PersistedQuery(
  *   id = "persisted_query_plugin_three",
  *   label = "Persisted Query Three",
  *   description = "This is the third persisted query plugin"
  * )
- *
- * Class PersistedQueryPluginThree
- * @package Drupal\graphql_persisted_queries_test\Plugin\GraphQL\PersistedQuery
  */
 class PersistedQueryPluginThree extends PersistedQueryPluginBase {
 
diff --git a/tests/modules/graphql_persisted_queries_test/src/Plugin/GraphQL/PersistedQuery/PersistedQueryPluginTwo.php b/tests/modules/graphql_persisted_queries_test/src/Plugin/GraphQL/PersistedQuery/PersistedQueryPluginTwo.php
index 13ab82a9bf193b13803807ffba35c3f1f7382d45..7b906612733a3c8550531b055cec3f5b783327cf 100644
--- a/tests/modules/graphql_persisted_queries_test/src/Plugin/GraphQL/PersistedQuery/PersistedQueryPluginTwo.php
+++ b/tests/modules/graphql_persisted_queries_test/src/Plugin/GraphQL/PersistedQuery/PersistedQueryPluginTwo.php
@@ -8,14 +8,13 @@ use Drupal\graphql\PersistedQuery\PersistedQueryPluginBase;
 use GraphQL\Server\OperationParams;
 
 /**
+ * Test persisted plugin.
+ *
  * @PersistedQuery(
  *   id = "persisted_query_plugin_two",
  *   label = "Persisted Query Two",
  *   description = "This is the second persisted query plugin"
  * )
- *
- * Class PersistedQueryPluginTwo
- * @package Drupal\graphql_persisted_queries_test\Plugin\GraphQL\PersistedQuery
  */
 class PersistedQueryPluginTwo extends PersistedQueryPluginBase {
 
diff --git a/tests/src/Kernel/AlterableSchemaTest.php b/tests/src/Kernel/AlterableSchemaTest.php
index bf8c639b894cdaaa10aaf2ee4e3ef7268f6d62d9..9402f474d846b53664c45793d0e0de999af38eef 100644
--- a/tests/src/Kernel/AlterableSchemaTest.php
+++ b/tests/src/Kernel/AlterableSchemaTest.php
@@ -148,10 +148,7 @@ class AlterableSchemaTest extends GraphQLTestBase {
       ->method('getBaseDefinition')
       ->willReturn('');
 
-    // Different extension definition for different tests.
-    // PHPUnit compatibility: remove once support for Drupal 10.2 is dropped.
-    $methodName = method_exists($this, 'name') ? 'name' : 'getName';
-    switch ($this->$methodName()) {
+    switch ($this->name()) {
       case 'testEmptySchemaExtensionAlteredQueryResultPropertyAdded':
         $extensionDefinition = '';
         break;
@@ -179,7 +176,10 @@ class AlterableSchemaTest extends GraphQLTestBase {
     // Replace mock schema with our own implementation.
     $this->schema = $this->getMockBuilder(AlterableComposableSchema::class)
       ->setConstructorArgs([
-        [],
+        [
+          'extensions' => ['graphql_alterable_schema_test' => 'graphql_alterable_schema_test'],
+          'server_id' => 'test_server',
+        ],
         $id,
         [],
         $this->container->get('cache.graphql.ast'),
@@ -188,7 +188,7 @@ class AlterableSchemaTest extends GraphQLTestBase {
         ['development' => FALSE],
         $this->container->get('event_dispatcher'),
       ])
-      ->onlyMethods(['getSchemaDefinition', 'getResolverRegistry', 'getConfiguration'])
+      ->onlyMethods(['getSchemaDefinition', 'getResolverRegistry'])
       ->getMock();
 
     $this->schema->expects(static::any())
@@ -199,9 +199,6 @@ class AlterableSchemaTest extends GraphQLTestBase {
     $this->schema->expects($this->any())
       ->method('getResolverRegistry')
       ->willReturn($this->registry);
-    $this->schema->expects($this->any())
-      ->method('getConfiguration')
-      ->willReturn(['extensions' => ['graphql_alterable_schema_test' => 'graphql_alterable_schema_test']]);
   }
 
 }
diff --git a/tests/src/Kernel/DataProducer/RoutingTest.php b/tests/src/Kernel/DataProducer/RoutingTest.php
index 6d02953fa0b6284d8ce7bbcc4356329b0591c9c8..7afb4fe1b1f33b040eb54899e87d4af5d30e5755 100644
--- a/tests/src/Kernel/DataProducer/RoutingTest.php
+++ b/tests/src/Kernel/DataProducer/RoutingTest.php
@@ -72,7 +72,6 @@ class RoutingTest extends GraphQLTestBase {
     $redirect->setRedirect($nodeUrl);
     $redirect->save();
 
-    /** @var \Drupal\Core\Url $result */
     $result = $this->executeDataProducer('route_load', [
       'path' => 'internal-url',
     ]);
diff --git a/tests/src/Kernel/EntityBufferTest.php b/tests/src/Kernel/EntityBufferTest.php
index 6edabef3d33e77b3c503c8c19f1c769c0bbb271d..367f2fa2cc7e774176cbb19ae7ede2d3b6eb80d0 100644
--- a/tests/src/Kernel/EntityBufferTest.php
+++ b/tests/src/Kernel/EntityBufferTest.php
@@ -14,11 +14,6 @@ use Drupal\node\Entity\NodeType;
  */
 class EntityBufferTest extends GraphQLTestBase {
 
-  /**
-   * @var array<string>
-   */
-  protected array $nodeIds = [];
-
   /**
    * {@inheritdoc}
    */
@@ -36,7 +31,6 @@ class EntityBufferTest extends GraphQLTestBase {
         'type' => 'test',
       ]);
       $node->save();
-      $this->nodeIds[] = $node->id();
     }
 
     $schema = <<<GQL
diff --git a/tests/src/Kernel/Framework/LoggerTest.php b/tests/src/Kernel/Framework/LoggerTest.php
index ee2cc000ce737557f86d3bb07f3f72a40eb2da63..2e28bf652e0e1dcdf449bd4e7e21fb6e901aecdf 100644
--- a/tests/src/Kernel/Framework/LoggerTest.php
+++ b/tests/src/Kernel/Framework/LoggerTest.php
@@ -52,9 +52,6 @@ GQL;
 
   /**
    * {@inheritdoc}
-   *
-   * @todo For some reason, PHPStan wants to see a type hint for the level here,
-   * which is not correct.
    */
   public function log($level, string|\Stringable $message, array $context = []): void {
     $this->loggerCalls[] = [
diff --git a/tests/src/Kernel/ResolverRegistryTest.php b/tests/src/Kernel/ResolverRegistryTest.php
index 018b7f345e7f9f1ce33d44ab57c15a1c59ec7520..6d931e9a19b6259c18e9f9b2096fe4d65306197a 100644
--- a/tests/src/Kernel/ResolverRegistryTest.php
+++ b/tests/src/Kernel/ResolverRegistryTest.php
@@ -4,8 +4,6 @@ declare(strict_types=1);
 
 namespace Drupal\Tests\graphql\Kernel;
 
-use Drupal\graphql\GraphQL\ResolverRegistry;
-
 /**
  * Tests that the resolver registry behaves correctly.
  *
@@ -41,11 +39,6 @@ class ResolverRegistryTest extends GraphQLTestBase {
 GQL;
 
     $this->setUpSchema($schema);
-
-    // Our mocking trait sets up the ResolverRegistry that we're interested in
-    // testing for us. This assertion guards against the mock implementation
-    // invalidating that and this test becoming useless.
-    self::assertInstanceOf(ResolverRegistry::class, $this->registry);
   }
 
   /**
diff --git a/tests/src/Kernel/ServerConfigurationTest.php b/tests/src/Kernel/ServerConfigurationTest.php
index fde20eb85d227380c9ad94f626abdd33852787d7..465a621425b9afa447fe126d842f2fa5d9715ec8 100644
--- a/tests/src/Kernel/ServerConfigurationTest.php
+++ b/tests/src/Kernel/ServerConfigurationTest.php
@@ -78,7 +78,6 @@ class ServerConfigurationTest extends GraphQLTestBase {
     // Replace the schema plugin manager with a mocked version that returns the
     // requested mocked schema extension plugins.
     $schemaPluginManager = $this->mockPluginManager(array_keys(self::TEST_SCHEMAS));
-    // @phpstan-ignore-next-line PHPStan doesn't find this method on the parent.
     $schemaPluginManager->method('createInstance')
       ->willReturnCallback(fn ($pluginId, $pluginConfig) => match ([$pluginId, $pluginConfig['server_id']]) {
         ['composable', $this->servers['node']->id()] => $this->extensionPlugins['node'],
diff --git a/tests/src/Kernel/ValidatorTest.php b/tests/src/Kernel/ValidatorTest.php
index 50acb5c0c1984db2f9e1c86a64a00235a3b09ce2..5f3ef73af9d0685fabd428b21eb3ee4e7b11951c 100644
--- a/tests/src/Kernel/ValidatorTest.php
+++ b/tests/src/Kernel/ValidatorTest.php
@@ -36,10 +36,12 @@ GQL;
   }
 
   /**
-   * @covers ::getMissingResolvers
+   * Test interfaces.
    *
    * Interfaces are ignored because the implementing types are used to check
    * whether a resolver is present.
+   *
+   * @covers ::getMissingResolvers
    */
   public function testGetMissingResolversIgnoresMissingFieldsOnInterfaces(): void {
     $schema = <<<GQL