diff --git src/wp-includes/rest-api/endpoints/class-wp-rest-controller.php src/wp-includes/rest-api/endpoints/class-wp-rest-controller.php
index 3bc6b59091..04bd1580f7 100644
--- src/wp-includes/rest-api/endpoints/class-wp-rest-controller.php
+++ src/wp-includes/rest-api/endpoints/class-wp-rest-controller.php
@@ -385,12 +385,18 @@ abstract class WP_REST_Controller {
 
 		$additional_fields = $this->get_additional_fields();
 
+		$requested_fields = $this->get_fields_for_response( $request );
+
 		foreach ( $additional_fields as $field_name => $field_options ) {
 
 			if ( ! $field_options['get_callback'] ) {
 				continue;
 			}
 
+			if ( ! in_array( $field_name, $requested_fields, true ) ) {
+				continue;
+			}
+
 			$object[ $field_name ] = call_user_func( $field_options['get_callback'], $object, $field_name, $request, $this->get_object_type() );
 		}
 
diff --git tests/phpunit/tests/rest-api/rest-controller.php tests/phpunit/tests/rest-api/rest-controller.php
index 88941ec1ee..b325fb19e2 100644
--- tests/phpunit/tests/rest-api/rest-controller.php
+++ tests/phpunit/tests/rest-api/rest-controller.php
@@ -213,4 +213,45 @@ class WP_Test_REST_Controller extends WP_Test_REST_TestCase {
 			'someinteger',
 		), $fields );
 	}
+
+	public function test_add_additional_fields_to_object_respects_fields_param() {
+		$controller = new WP_REST_Test_Controller();
+		$request    = new WP_REST_Request( 'GET', '/wp/v2/testroute' );
+		$schema     = $controller->get_item_schema();
+		$field      = 'somefield';
+
+		$listener = new MockAction();
+		$method = 'action';
+
+		register_rest_field(
+			$schema['title'],
+			$field,
+			array(
+				'get_callback' => array( $listener, $method ),
+				'schema'       => array(
+					'type' => 'string',
+				),
+			)
+		);
+
+		$item = [];
+
+		$controller->prepare_item_for_response( $item, $request );
+
+		$first_call_count = $listener->get_call_count( $method );
+
+		$this->assertTrue( $first_call_count > 0 );
+
+		$request->set_param( '_fields', 'somestring' );
+
+		$controller->prepare_item_for_response( $item, $request );
+
+		$this->assertSame( $first_call_count, $listener->get_call_count( $method ) );
+
+		$request->set_param( '_fields', $field );
+
+		$controller->prepare_item_for_response( $item, $request );
+
+		$this->assertTrue( $listener->get_call_count( $method ) > $first_call_count );
+	}
 }
diff --git tests/phpunit/tests/rest-api/rest-test-controller.php tests/phpunit/tests/rest-api/rest-test-controller.php
index 5b90f76e44..a8c3fefe0a 100644
--- tests/phpunit/tests/rest-api/rest-test-controller.php
+++ tests/phpunit/tests/rest-api/rest-test-controller.php
@@ -10,9 +10,23 @@
  * @group restapi
  */
 class WP_REST_Test_Controller extends WP_REST_Controller {
+	/**
+	 * Prepares the item for the REST response.
+	 *
+	 * @param mixed           $item    WordPress representation of the item.
+	 * @param WP_REST_Request $request Request object.
+	 * @return WP_Error|WP_REST_Response Response object on success, or WP_Error object on failure.
+	 */
+	public function prepare_item_for_response( $item, $request ) {
+		$context = ! empty( $request['context'] ) ? $request['context'] : 'view';
+		$item = $this->add_additional_fields_to_object( $item, $request );
+		$item = $this->filter_response_by_context( $item, $context );
+		$response = rest_ensure_response( $item );
+		return $response;
+	}
 
 	/**
-	 * Get the Post type's schema, conforming to JSON Schema
+	 * Get the item's schema, conforming to JSON Schema.
 	 *
 	 * @return array
 	 */
@@ -72,7 +86,7 @@ class WP_REST_Test_Controller extends WP_REST_Controller {
 			),
 		);
 
-		return $schema;
+		return $this->add_additional_fields_schema( $schema );
 	}
 
 }
