diff --git a/src/JsonSchema/SchemaFactory.php b/src/JsonSchema/SchemaFactory.php
index 097eaddd4b8..e853087d397 100644
--- a/src/JsonSchema/SchemaFactory.php
+++ b/src/JsonSchema/SchemaFactory.php
@@ -88,6 +88,19 @@ public function buildSchema(string $className, string $format = 'json', string $
             return $schema;
         }
 
+        $isJsonMergePatch = 'json' === $format && 'PATCH' === $operation->getMethod() && Schema::TYPE_INPUT === $type;
+        $skipRequiredProperties = false;
+
+        if ($isJsonMergePatch) {
+            if (null === ($skipRequiredProperties = $operation->getExtraProperties()['patch_skip_schema_required_properties'] ?? null)) {
+                trigger_deprecation('api-platform/core', '3.4', "Set 'patch_skip_schema_required_properties' on extra properties as API Platform 4 will remove required properties from the JSON Schema on Patch request.");
+            }
+
+            if (true === $skipRequiredProperties) {
+                $definitionName .= self::PATCH_SCHEMA_POSTFIX;
+            }
+        }
+
         if (!isset($schema['$ref']) && !isset($schema['type'])) {
             $ref = Schema::VERSION_OPENAPI === $version ? '#/components/schemas/'.$definitionName : '#/definitions/'.$definitionName;
             if ($forceCollection || ('POST' !== $method && $operation instanceof CollectionOperationInterface)) {
@@ -129,6 +142,7 @@ public function buildSchema(string $className, string $format = 'json', string $
         }
 
         $options = ['schema_type' => $type] + $this->getFactoryOptions($serializerContext, $validationGroups, $operation instanceof HttpOperation ? $operation : null);
+
         foreach ($this->propertyNameCollectionFactory->create($inputOrOutputClass, $options) as $propertyName) {
             $propertyMetadata = $this->propertyMetadataFactory->create($inputOrOutputClass, $propertyName, $options);
             if (!$propertyMetadata->isReadable() && !$propertyMetadata->isWritable()) {
@@ -136,7 +150,7 @@ public function buildSchema(string $className, string $format = 'json', string $
             }
 
             $normalizedPropertyName = $this->nameConverter ? $this->nameConverter->normalize($propertyName, $inputOrOutputClass, $format, $serializerContext) : $propertyName;
-            if ($propertyMetadata->isRequired()) {
+            if ($propertyMetadata->isRequired() && !$skipRequiredProperties) {
                 $definition['required'][] = $normalizedPropertyName;
             }
 
diff --git a/tests/Fixtures/TestBundle/ApiResource/PatchRequired/PatchMe.php b/tests/Fixtures/TestBundle/ApiResource/PatchRequired/PatchMe.php
new file mode 100644
index 00000000000..a5573da4856
--- /dev/null
+++ b/tests/Fixtures/TestBundle/ApiResource/PatchRequired/PatchMe.php
@@ -0,0 +1,30 @@
+<?php
+
+/*
+ * This file is part of the API Platform project.
+ *
+ * (c) Kévin Dunglas <dunglas@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+declare(strict_types=1);
+
+namespace ApiPlatform\Tests\Fixtures\TestBundle\ApiResource\PatchRequired;
+
+use ApiPlatform\Metadata\Patch;
+use Symfony\Component\Validator\Constraints\NotNull;
+
+#[Patch(uriTemplate: '/patch_required_stuff', provider: [self::class, 'provide'])]
+final class PatchMe
+{
+    public ?string $a = null;
+    #[NotNull]
+    public ?string $b = null;
+
+    public static function provide(): self
+    {
+        return new self();
+    }
+}
diff --git a/tests/JsonSchema/Command/JsonSchemaGenerateCommandTest.php b/tests/JsonSchema/Command/JsonSchemaGenerateCommandTest.php
index ed68a69e50e..b65fce63480 100644
--- a/tests/JsonSchema/Command/JsonSchemaGenerateCommandTest.php
+++ b/tests/JsonSchema/Command/JsonSchemaGenerateCommandTest.php
@@ -15,6 +15,7 @@
 
 use ApiPlatform\Tests\Fixtures\TestBundle\Document\Dummy as DocumentDummy;
 use ApiPlatform\Tests\Fixtures\TestBundle\Entity\Dummy;
+use Symfony\Bridge\PhpUnit\ExpectDeprecationTrait;
 use Symfony\Bundle\FrameworkBundle\Console\Application;
 use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
 use Symfony\Component\Console\Tester\ApplicationTester;
@@ -24,6 +25,7 @@
  */
 class JsonSchemaGenerateCommandTest extends KernelTestCase
 {
+    use ExpectDeprecationTrait;
     private ApplicationTester $tester;
 
     private string $entityClass;
@@ -76,9 +78,9 @@ public function testExecuteWithJsonldTypeInput(): void
         $this->tester->run(['command' => 'api:json-schema:generate', 'resource' => $this->entityClass, '--operation' => '_api_/dummies{._format}_post', '--format' => 'jsonld', '--type' => 'input']);
         $result = $this->tester->getDisplay();
 
-        $this->assertStringContainsString('@id', $result);
-        $this->assertStringContainsString('@context', $result);
-        $this->assertStringContainsString('@type', $result);
+        $this->assertStringNotContainsString('@id', $result);
+        $this->assertStringNotContainsString('@context', $result);
+        $this->assertStringNotContainsString('@type', $result);
     }
 
     /**
@@ -103,24 +105,24 @@ public function testArraySchemaWithReference(): void
         $result = $this->tester->getDisplay();
         $json = json_decode($result, associative: true);
 
-        $this->assertEquals($json['definitions']['BagOfTests.jsonld-write.input']['properties']['tests'], [
+        $this->assertEquals($json['definitions']['BagOfTests.jsonld-write']['properties']['tests'], [
             'type' => 'string',
             'foo' => 'bar',
         ]);
 
-        $this->assertEquals($json['definitions']['BagOfTests.jsonld-write.input']['properties']['nonResourceTests'], [
+        $this->assertEquals($json['definitions']['BagOfTests.jsonld-write']['properties']['nonResourceTests'], [
             'type' => 'array',
             'items' => [
-                '$ref' => '#/definitions/NonResourceTestEntity.jsonld-write.input',
+                '$ref' => '#/definitions/NonResourceTestEntity.jsonld-write',
             ],
         ]);
 
-        $this->assertEquals($json['definitions']['BagOfTests.jsonld-write.input']['properties']['description'], [
+        $this->assertEquals($json['definitions']['BagOfTests.jsonld-write']['properties']['description'], [
             'maxLength' => 255,
         ]);
 
-        $this->assertEquals($json['definitions']['BagOfTests.jsonld-write.input']['properties']['type'], [
-            '$ref' => '#/definitions/TestEntity.jsonld-write.input',
+        $this->assertEquals($json['definitions']['BagOfTests.jsonld-write']['properties']['type'], [
+            '$ref' => '#/definitions/TestEntity.jsonld-write',
         ]);
     }
 
@@ -130,14 +132,14 @@ public function testArraySchemaWithMultipleUnionTypesJsonLd(): void
         $result = $this->tester->getDisplay();
         $json = json_decode($result, associative: true);
 
-        $this->assertEquals($json['definitions']['Nest.jsonld.output']['properties']['owner']['anyOf'], [
-            ['$ref' => '#/definitions/Wren.jsonld.output'],
-            ['$ref' => '#/definitions/Robin.jsonld.output'],
+        $this->assertEquals($json['definitions']['Nest.jsonld']['properties']['owner']['anyOf'], [
+            ['$ref' => '#/definitions/Wren.jsonld'],
+            ['$ref' => '#/definitions/Robin.jsonld'],
             ['type' => 'null'],
         ]);
 
-        $this->assertArrayHasKey('Wren.jsonld.output', $json['definitions']);
-        $this->assertArrayHasKey('Robin.jsonld.output', $json['definitions']);
+        $this->assertArrayHasKey('Wren.jsonld', $json['definitions']);
+        $this->assertArrayHasKey('Robin.jsonld', $json['definitions']);
     }
 
     public function testArraySchemaWithMultipleUnionTypesJsonApi(): void
@@ -183,7 +185,7 @@ public function testArraySchemaWithTypeFactory(): void
         $result = $this->tester->getDisplay();
         $json = json_decode($result, associative: true);
 
-        $this->assertEquals($json['definitions']['Foo.jsonld.output']['properties']['expiration'], ['type' => 'string', 'format' => 'date']);
+        $this->assertEquals($json['definitions']['Foo.jsonld']['properties']['expiration'], ['type' => 'string', 'format' => 'date']);
     }
 
     /**
@@ -195,7 +197,7 @@ public function testWritableNonResourceRef(): void
         $result = $this->tester->getDisplay();
         $json = json_decode($result, associative: true);
 
-        $this->assertEquals($json['definitions']['SaveProduct.jsonld.input']['properties']['codes']['items']['$ref'], '#/definitions/ProductCode.jsonld.input');
+        $this->assertEquals($json['definitions']['SaveProduct.jsonld']['properties']['codes']['items']['$ref'], '#/definitions/ProductCode.jsonld');
     }
 
     /**
@@ -207,8 +209,8 @@ public function testOpenApiResourceRefIsNotOverwritten(): void
         $result = $this->tester->getDisplay();
         $json = json_decode($result, associative: true);
 
-        $this->assertEquals('#/definitions/DummyFriend', $json['definitions']['Issue6299.Issue6299OutputDto.jsonld.output']['properties']['itemDto']['$ref']);
-        $this->assertEquals('#/definitions/DummyDate', $json['definitions']['Issue6299.Issue6299OutputDto.jsonld.output']['properties']['collectionDto']['items']['$ref']);
+        $this->assertEquals('#/definitions/DummyFriend', $json['definitions']['Issue6299.Issue6299OutputDto.jsonld']['properties']['itemDto']['$ref']);
+        $this->assertEquals('#/definitions/DummyDate', $json['definitions']['Issue6299.Issue6299OutputDto.jsonld']['properties']['collectionDto']['items']['$ref']);
     }
 
     /**
@@ -220,7 +222,7 @@ public function testSubSchemaJsonLd(): void
         $result = $this->tester->getDisplay();
         $json = json_decode($result, associative: true);
 
-        $this->assertArrayHasKey('@id', $json['definitions']['ThirdLevel.jsonld-friends.output']['properties']);
+        $this->assertArrayHasKey('@id', $json['definitions']['ThirdLevel.jsonld-friends']['properties']);
     }
 
     public function testJsonApiIncludesSchema(): void
@@ -332,4 +334,17 @@ public function testResourceWithEnumPropertiesSchema(): void
             $properties['genders']
         );
     }
+
+    /**
+     * @group legacy
+     * TODO: find a way to keep required properties if needed
+     */
+    public function testPatchSchemaRequiredProperties(): void
+    {
+        $this->tester->run(['command' => 'api:json-schema:generate', 'resource' => 'ApiPlatform\Tests\Fixtures\TestBundle\ApiResource\PatchRequired\PatchMe', '--format' => 'json']);
+        $result = $this->tester->getDisplay();
+        $json = json_decode($result, associative: true);
+
+        $this->assertEquals(['b'], $json['definitions']['PatchMe']['required']);
+    }
 }