diff --git a/core/modules/jsonapi/src/Context/FieldResolver.php b/core/modules/jsonapi/src/Context/FieldResolver.php
index 7da702576d5ae094a73e68cf24cf630debdb1074..ab410e9b93c7f115f2bf980e9d920f9d72fc4620 100644
--- a/core/modules/jsonapi/src/Context/FieldResolver.php
+++ b/core/modules/jsonapi/src/Context/FieldResolver.php
@@ -256,13 +256,16 @@ public static function resolveInternalIncludePath(ResourceType $resource_type, a
    *   The JSON:API resource type from which to resolve the field name.
    * @param string $external_field_name
    *   The public field name to map to a Drupal field name.
+   * @param string $operator
+   *   (optional) The operator of the condition for which the path should be
+   *   resolved.
    *
    * @return string
    *   The mapped field name.
    *
    * @throws \Drupal\Core\Http\Exception\CacheableBadRequestHttpException
    */
-  public function resolveInternalEntityQueryPath(ResourceType $resource_type, $external_field_name) {
+  public function resolveInternalEntityQueryPath(ResourceType $resource_type, $external_field_name, $operator = NULL) {
     $cacheability = (new CacheableMetadata())->addCacheContexts(['url.query_args:filter', 'url.query_args:sort']);
     if (empty($external_field_name)) {
       throw new CacheableBadRequestHttpException($cacheability, 'No field name was provided for the filter.');
@@ -355,7 +358,10 @@ public function resolveInternalEntityQueryPath(ResourceType $resource_type, $ext
       // If there are no remaining path parts, the process is finished unless
       // the field has multiple properties, in which case one must be specified.
       if (empty($parts)) {
-        if ($property_specifier_needed) {
+        // If the operator is asserting the presence or absence of a
+        // relationship entirely, it does not make sense to require a property
+        // specifier.
+        if ($property_specifier_needed && (!$at_least_one_entity_reference_field || !in_array($operator, ['IS NULL', 'IS NOT NULL'], TRUE))) {
           $possible_specifiers = array_map(function ($specifier) use ($at_least_one_entity_reference_field) {
             return $at_least_one_entity_reference_field && $specifier !== 'id' ? "meta.$specifier" : $specifier;
           }, $candidate_property_names);
diff --git a/core/modules/jsonapi/src/Query/Filter.php b/core/modules/jsonapi/src/Query/Filter.php
index e87f0081a45aa8c3b0ede2a026040efc7a4b4d79..2ca708b433ff192357976f1c23c83b4c1743233f 100644
--- a/core/modules/jsonapi/src/Query/Filter.php
+++ b/core/modules/jsonapi/src/Query/Filter.php
@@ -157,7 +157,8 @@ public static function createFromQueryParameter($parameter, ResourceType $resour
     foreach ($expanded as &$filter_item) {
       if (isset($filter_item[static::CONDITION_KEY][EntityCondition::PATH_KEY])) {
         $unresolved = $filter_item[static::CONDITION_KEY][EntityCondition::PATH_KEY];
-        $filter_item[static::CONDITION_KEY][EntityCondition::PATH_KEY] = $field_resolver->resolveInternalEntityQueryPath($resource_type, $unresolved);
+        $operator = $filter_item[static::CONDITION_KEY][EntityCondition::OPERATOR_KEY];
+        $filter_item[static::CONDITION_KEY][EntityCondition::PATH_KEY] = $field_resolver->resolveInternalEntityQueryPath($resource_type, $unresolved, $operator);
       }
     }
     return new static(static::buildEntityConditionGroup($expanded));
diff --git a/core/modules/jsonapi/tests/src/Functional/JsonApiRegressionTest.php b/core/modules/jsonapi/tests/src/Functional/JsonApiRegressionTest.php
index ea78b4f53f2a68b1f47f18af2d51eb76de18c187..35379fa1f065fad94e0049cb84990ab7d298c93c 100644
--- a/core/modules/jsonapi/tests/src/Functional/JsonApiRegressionTest.php
+++ b/core/modules/jsonapi/tests/src/Functional/JsonApiRegressionTest.php
@@ -918,6 +918,62 @@ public function testMapFieldTypeNormalizationFromIssue3040590() {
     $this->assertSame(['foo' => 'bar'], $data['data'][0]['attributes']['data']);
   }
 
+  /**
+   * Ensure filtering for entities with empty entity reference fields works.
+   *
+   * @see https://www.drupal.org/project/jsonapi/issues/3025372
+   */
+  public function testEmptyRelationshipFilteringFromIssue3025372() {
+    // Set up data model.
+    $this->drupalCreateContentType(['type' => 'folder']);
+    $this->createEntityReferenceField(
+      'node',
+      'folder',
+      'field_parent_folder',
+      NULL,
+      'node',
+      'default',
+      [
+        'target_bundles' => ['folder'],
+      ],
+      FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED
+    );
+    $this->rebuildAll();
+
+    // Create data.
+    $node = Node::create([
+      'title' => 'root folder',
+      'type' => 'folder',
+    ]);
+    $node->save();
+
+    // Test.
+    $user = $this->drupalCreateUser(['access content']);
+    $url = Url::fromRoute('jsonapi.node--folder.collection');
+    $request_options = [
+      RequestOptions::HEADERS => [
+        'Content-Type' => 'application/vnd.api+json',
+        'Accept' => 'application/vnd.api+json',
+      ],
+      RequestOptions::AUTH => [$user->getAccountName(), $user->pass_raw],
+    ];
+    $response = $this->request('GET', $url, $request_options);
+    $this->assertSame(200, $response->getStatusCode(), (string) $response->getBody());
+    $this->assertSame($node->uuid(), Json::decode((string) $response->getBody())['data'][0]['id']);
+    $response = $this->request('GET', $url->setOption('query', [
+      'filter[test][condition][path]' => 'field_parent_folder',
+      'filter[test][condition][operator]' => 'IS NULL',
+    ]), $request_options);
+    $this->assertSame(200, $response->getStatusCode(), (string) $response->getBody());
+    $this->assertSame($node->uuid(), Json::decode((string) $response->getBody())['data'][0]['id']);
+    $response = $this->request('GET', $url->setOption('query', [
+      'filter[test][condition][path]' => 'field_parent_folder',
+      'filter[test][condition][operator]' => 'IS NOT NULL',
+    ]), $request_options);
+    $this->assertSame(200, $response->getStatusCode(), (string) $response->getBody());
+    $this->assertEmpty(Json::decode((string) $response->getBody())['data']);
+  }
+
   /**
    * Tests that the response still has meaningful error messages.
    */
diff --git a/core/modules/jsonapi/tests/src/Kernel/Query/FilterTest.php b/core/modules/jsonapi/tests/src/Kernel/Query/FilterTest.php
index 66c06900136529866779b89b5080cfc06c553b37..4adb923590b94493d8a537916f6c5da0cffa0786 100644
--- a/core/modules/jsonapi/tests/src/Kernel/Query/FilterTest.php
+++ b/core/modules/jsonapi/tests/src/Kernel/Query/FilterTest.php
@@ -413,7 +413,7 @@ public function testCreateFromQueryParameterNested() {
    */
   protected function getFieldResolverMock(ResourceType $resource_type) {
     $field_resolver = $this->prophesize(FieldResolver::class);
-    $field_resolver->resolveInternalEntityQueryPath($resource_type, Argument::any())->willReturnArgument(1);
+    $field_resolver->resolveInternalEntityQueryPath($resource_type, Argument::any(), Argument::any())->willReturnArgument(1);
     return $field_resolver->reveal();
   }