diff --git a/src/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php b/src/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php
index d0333c61c4..4dfd280e8b 100644
--- a/src/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php
+++ b/src/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php
@@ -2260,8 +2260,33 @@ class WP_REST_Posts_Controller extends WP_REST_Controller {
 			$schema['links'] = $schema_links;
 		}
 
+		$schema = $this->add_additional_fields_schema( $schema );
+
+		/**
+		 * Filter the post's schema.
+		 *
+		 * The dynamic part of the filter `$this->post_type` refers to the post
+		 * type slug for the controller.
+		 *
+		 * @since 5.3.0
+		 *
+		 * @param array  $schema  Item schema data.
+		 */
+
+		$schema_fields = array_keys( $schema['properties'] );
+
+		$schema = apply_filters( "rest_{$this->post_type}_item_schema", $schema );
+
+		$new_fields = array_diff( array_keys( $schema['properties'] ), $schema_fields );
+
+		// Emit a _doing_it_wrong warning if user tries to add new properties using this filter.
+		if ( count( $new_fields ) > 0 ) {
+			_doing_it_wrong( __METHOD__, __( 'Please use register_rest_field to add new properties.' ), '5.3.0' );
+		}
+
 		$this->schema = $schema;
-		return $this->add_additional_fields_schema( $this->schema );
+
+		return $schema;
 	}
 
 	/**
diff --git a/tests/phpunit/tests/rest-api/rest-posts-controller.php b/tests/phpunit/tests/rest-api/rest-posts-controller.php
index 2aca849347..d935d985c6 100644
--- a/tests/phpunit/tests/rest-api/rest-posts-controller.php
+++ b/tests/phpunit/tests/rest-api/rest-posts-controller.php
@@ -4827,6 +4827,31 @@ class WP_Test_REST_Posts_Controller extends WP_Test_REST_Post_Type_Controller_Te
 		$this->assertNull( get_post_type_object( 'test' )->get_rest_controller() );
 	}
 
+
+	/**
+	* @ticket 47779
+	 */
+	public function test_rest_post_type_item_schema_filter_change_property() {
+		add_filter( 'rest_post_item_schema', array( $this, 'filter_post_item_schema' ) );
+
+		// Re-initialize the controller to cache-bust schemas from prior test runs.
+		$GLOBALS['wp_rest_server']->override_by_default = true;
+		$controller                                     = new WP_REST_Posts_Controller( 'post' );
+		$controller->register_routes();
+		$GLOBALS['wp_rest_server']->override_by_default = false;
+
+		$request    = new WP_REST_Request( 'OPTIONS', '/wp/v2/posts' );
+		$response   = rest_get_server()->dispatch( $request );
+		$data       = $response->get_data();
+		$properties = $data['schema']['properties']['content']['properties'];
+
+		remove_filter( 'rest_post_item_schema', array( $this, 'filter_post_item_schema' ) );
+
+		$this->assertArrayHasKey( 'new_prop', $properties );
+		$this->assertEquals( array( 'new_context' ), $properties['new_prop']['context'] );
+	}
+
+
 	public function tearDown() {
 		_unregister_post_type( 'private-post' );
 		_unregister_post_type( 'youseeme' );
@@ -4854,4 +4879,13 @@ class WP_Test_REST_Posts_Controller extends WP_Test_REST_Post_Type_Controller_Te
 			'post-my-test-template.php' => 'My Test Template',
 		);
 	}
+
+	public function filter_post_item_schema( $schema ) {
+		$schema['properties']['content']['properties']['new_prop'] = array(
+			'description' => __( 'A new prop added with a the rest_post_item_schema filter.' ),
+			'type'        => 'string',
+			'context'     => array( 'new_context' ),
+		);
+		return $schema;
+	}
 }
