diff --git a/src/wp-includes/meta.php b/src/wp-includes/meta.php
index 718f42a..0b7033e 100644
--- a/src/wp-includes/meta.php
+++ b/src/wp-includes/meta.php
@@ -1075,23 +1075,37 @@ function register_meta( $object_type, $meta_key, $args, $deprecated = null ) {
 		}
 	}

+	$object_subtype = '';
+
+	if ( ! empty( $args['object_subtype'] ) ) {
+		$object_subtype = $args['object_subtype'];
+	}
+
 	// Back-compat: old sanitize and auth callbacks applied to all of an object type
 	if ( $has_old_sanitize_cb ) {
 		add_filter( "sanitize_{$object_type}_meta_{$meta_key}", $args['sanitize_callback'], 10, 4 );
 		add_filter( "auth_{$object_type}_meta_{$meta_key}", $args['auth_callback'], 10, 6 );
 	} else {
+		// Back-compat: old sanitize and auth callbacks applied to all of an object type
 		if ( is_callable( $args['sanitize_callback'] ) ) {
-			add_filter( "sanitize_{$object_type}_{$object_subtype}_meta_{$meta_key}", $args['sanitize_callback'], 10, 4 );
+			if ( empty( $object_subtype ) || $has_old_sanitize_cb ) {
+				add_filter( "sanitize_{$object_type}_meta_{$meta_key}", $args['sanitize_callback'], 10, 4 );
+			} else {
+				add_filter( "sanitize_{$object_type}_{$object_subtype}_meta_{$meta_key}", $args['sanitize_callback'], 10, 4 );
+			}
 		}

 		if ( is_callable( $args['auth_callback'] ) ) {
-			add_filter( "auth_{$object_type}_{$object_subtype}_meta_{$meta_key}", $args['auth_callback'], 10, 6 );
+			if ( empty( $object_subtype ) || $has_old_sanitize_cb ) {
+				add_filter( "auth_{$object_type}_meta_{$meta_key}", $args['auth_callback'], 10, 6 );
+			} else {
+				add_filter( "auth_{$object_type}_{$object_subtype}_meta_{$meta_key}", $args['auth_callback'], 10, 6 );
+			}
 		}
 	}

 	// Global registry only contains meta keys registered in the new way with a subtype.
-	if ( ! empty( $args['object_subtype'] ) ) {
-		$object_subtype = $args['object_subtype'];
+	if ( ! empty( $object_subtype ) ) {
 		$wp_meta_keys[ $object_type ][ $object_subtype ][ $meta_key ] = $args;

 		return true;
@@ -1234,7 +1248,7 @@ function get_registered_metadata( $object_type, $object_subtype, $object_id, $me
 		return $data;
 	}

-	$data = get_metadata( $object_type, $object_id, $meta_key );
+	$data = get_metadata( $object_type, $object_id );

 	$meta_keys = get_registered_meta_keys( $object_type, $object_subtype );
 	$registered_data = array();
diff --git a/tests/phpunit/tests/meta/registerMeta.php b/tests/phpunit/tests/meta/registerMeta.php
new file mode 100644
index 0000000..cbd604e
--- /dev/null
+++ b/tests/phpunit/tests/meta/registerMeta.php
@@ -0,0 +1,205 @@
+<?php
+/**
+ * @group meta
+ */
+class Tests_Meta_Register_Meta extends WP_UnitTestCase {
+	protected static $editor_id;
+	protected static $post_id;
+	protected static $comment_id;
+
+	public static function wpSetUpBeforeClass( $factory ) {
+		self::$editor_id = $factory->user->create( array( 'role' => 'editor' ) );
+		self::$post_id = $factory->post->create();
+		self::$comment_id = $factory->comment->create( array( 'comment_post_ID' => self::$post_id ) );
+	}
+
+	public static function wpTearDownAfterClass() {
+		self::delete_user( self::$editor_id );
+		wp_delete_comment( self::$comment_id, true );
+		wp_delete_post( self::$post_id, true );
+	}
+
+	function setUp() {
+		parent::setUp();
+		wp_set_current_user( self::$editor_id );
+	}
+
+	public function _old_sanitize_meta_cb( $meta_value, $meta_key, $meta_type ) {
+		return $meta_key . ' sanitized';
+	}
+
+	public function _new_sanitize_meta_cb( $meta_value, $meta_key, $object_type, $object_subtype ) {
+		return $meta_key . ' sanitized';
+	}
+
+	public function test_register_meta() {
+		$this->assertTrue( register_meta( 'post', 'flight_number', array( 'object_subtype' => 'post' ) ) );
+	}
+
+	public function test_register_meta_without_subtype() {
+		$this->assertFalse( register_meta( 'post', 'flight_number', array( $this, '_new_sanitize_meta_cb' ) ) );
+	}
+
+	public function test_register_meta_without_sanitize_callback_registers_meta_key() {
+		register_meta( 'post', 'flight_number', array( 'object_subtype' => 'post' ) );
+		$this->assertTrue( registered_meta_key_exists( 'post', 'post', 'flight_number' ) );
+	}
+
+	public function test_register_meta_for_a_category() {
+		register_meta( 'term', 'category_icon', array( 'object_subtype' => 'category' ) );
+		$this->assertTrue( registered_meta_key_exists( 'term', 'category', 'category_icon' ) );
+	}
+
+	public function test_register_meta_for_a_comment() {
+		register_meta( 'comment', 'comment_rating', array( 'object_subtype' => 'comment' ) );
+		$this->assertTrue( registered_meta_key_exists( 'comment', 'comment', 'comment_rating' ) );
+	}
+
+	public function test_register_meta_with_sanitize_callback_registers_meta_key() {
+		register_meta( 'post', 'flight_number', array( 'object_subtype' => 'post', 'sanitize_callback' => array( $this, '_new_sanitize_meta_cb' ) ) );
+		$this->assertTrue( registered_meta_key_exists( 'post', 'post', 'flight_number' ) );
+	}
+
+	public function test_register_meta_valid_object_type_with_valid_type() {
+		register_meta( 'post', 'longitude', array( 'object_subtype' => 'post' ) );
+		$this->assertTrue( registered_meta_key_exists( 'post', 'post', 'longitude' ) );
+	}
+
+	public function test_register_meta_valid_object_type_with_invalid_subtype() {
+		register_meta( 'post', 'latitude', array( 'object_subtype' => 'post' ) );
+		$this->assertFalse( registered_meta_key_exists( 'post', 'invalid-type', 'latitude' ) );
+	}
+
+	public function test_register_meta_with_old_sanitize_callback_parameter() {
+		register_meta( 'post', 'old_sanitized_key', array( $this, '_old_sanitize_meta_cb' ) );
+		$meta = sanitize_meta( 'old_sanitized_key', 'unsanitized', 'post', 'post' );
+
+		$this->assertEquals( 'old_sanitized_key sanitized', $meta );
+	}
+
+	public function test_register_meta_with_new_sanitize_callback_parameter() {
+		register_meta( 'post', 'new_sanitized_key', array( 'object_subtype' => 'post', 'sanitize_callback' => array( $this, '_new_sanitize_meta_cb' ) ) );
+		$meta = sanitize_meta( 'new_sanitized_key', 'unsanitized', 'post', 'post' );
+
+		$this->assertEquals( 'new_sanitized_key sanitized', $meta );
+	}
+
+	public function test_unregister_meta_key() {
+		register_meta( 'post', 'registered_key', array( 'object_subtype' => 'post' ) );
+
+		$this->assertTrue( unregister_meta_key( 'post', 'post', 'registered_key' ) );
+	}
+
+	public function test_unregister_meta_key_with_invalid_key() {
+		$this->assertWPError( unregister_meta_key( 'post', 'post', 'not_a_registered_key' ) );
+	}
+
+	public function test_get_registered_meta_keys() {
+		register_meta( 'post', 'registered_key1', array( 'object_subtype' => 'post' ) );
+		register_meta( 'post', 'registered_key2', array( 'object_subtype' => 'post' ) );
+
+		$meta_keys = get_registered_meta_keys( 'post', 'post' );
+
+		$this->assertArrayHasKey( 'registered_key1', $meta_keys );
+		$this->assertArrayHasKey( 'registered_key2', $meta_keys );
+	}
+
+	public function test_get_registered_meta_keys_subtype_is_empty() {
+		register_meta( 'post', 'registered_key1', array( 'object_subtype' => 'post' ) );
+		register_meta( 'post', 'registered_key2', array( 'object_subtype' => 'post' ) );
+
+		$meta_keys = get_registered_meta_keys( 'post', 'page' );
+
+		$this->assertEmpty( $meta_keys );
+	}
+
+	public function test_get_registered_meta_keys_invalid_type_is_empty() {
+		register_meta( 'post', 'registered_key1', array( 'object_subtype' => 'post' ) );
+		register_meta( 'post', 'registered_key2', array( 'object_subtype' => 'post' ) );
+
+		$meta_keys = get_registered_meta_keys( 'invalid-type' );
+
+		$this->assertEmpty( $meta_keys );
+	}
+
+	public function test_get_registered_meta_keys_has_count() {
+		register_meta( 'post', 'registered_key1', array( 'object_subtype' => 'post' ) );
+		register_meta( 'post', 'registered_key2', array( 'object_subtype' => 'page' ) );
+
+		$meta_keys = get_registered_meta_keys( 'post' );
+
+		$this->assertCount( 2, $meta_keys );
+	}
+
+	public function test_get_registered_meta_keys_type_arg() {
+		register_meta( 'post', 'registered_key1', array( 'object_subtype' => 'post', 'description' => 'I\'m just a field, take a good look at me' ) );
+
+		$meta_keys = get_registered_meta_keys( 'post', 'post' );
+
+		$this->assertEquals( 'I\'m just a field, take a good look at me', $meta_keys['registered_key1']['description'] );
+	}
+
+	public function test_get_registered_meta_keys_invalid_arg() {
+		register_meta( 'post', 'registered_key1', array( 'object_subtype' => 'post', 'invalid_arg' => 'invalid' ) );
+
+		$meta_keys = get_registered_meta_keys( 'post', 'post' );
+
+		$this->assertArrayNotHasKey( 'invalid_arg', $meta_keys['registered_key1'] );
+	}
+
+	public function test_get_registered_metadata() {
+		register_meta( 'post', 'flight_number', array( 'object_subtype' => 'post' ) );
+
+		add_post_meta( self::$post_id, 'flight_number', 'Oceanic 815' );
+
+		$meta = get_registered_metadata( 'post', 'post', self::$post_id );
+
+		$this->assertEquals( 'Oceanic 815', $meta['flight_number'][0] );
+	}
+
+	public function test_get_registered_metadata_by_key() {
+		register_meta( 'post', 'flight_number', array( 'object_subtype' => 'post' ) );
+
+		add_post_meta( self::$post_id, 'flight_number', 'Oceanic 815' );
+
+		$meta = get_registered_metadata( 'post', 'post', self::$post_id, 'flight_number' );
+
+		$this->assertEquals( 'Oceanic 815', $meta[0] );
+	}
+
+	public function test_get_registered_metadata_by_key_single() {
+		register_meta( 'post', 'flight_number', array( 'object_subtype' => 'post', 'single' => true ) );
+
+		add_post_meta( self::$post_id, 'flight_number', 'Oceanic 815' );
+
+		$meta = get_registered_metadata( 'post', 'post', self::$post_id, 'flight_number' );
+
+		$this->assertEquals( 'Oceanic 815', $meta );
+	}
+
+	public function test_get_registered_metadata_by_invalid_key() {
+		register_meta( 'post', 'flight_number', array( 'object_subtype' => 'post' ) );
+
+		add_post_meta( self::$post_id, 'flight_number', 'Oceanic 815' );
+
+		$meta = get_registered_metadata( 'post', 'post', self::$post_id, 'flight_pilot' );
+
+		$this->assertWPError( $meta );
+	}
+
+	public function test_get_registered_metadata_invalid_object_type() {
+		register_meta( 'post', 'flight_number', array( 'object_subtype' => 'post' ) );
+
+		add_post_meta( self::$post_id, 'flight_number', 'Oceanic 815' );
+
+		$meta = get_registered_metadata( 'invalid-type', 'invalid-subtype', self::$post_id );
+
+		$this->assertWPError( $meta );
+	}
+
+	public function test_get_registered_metadata_invalid() {
+		$meta = get_registered_metadata( 'invalid-type', 'invalid-subtype', self::$post_id );
+
+		$this->assertWPError( $meta );
+	}
+}
\ No newline at end of file
diff --git a/tests/phpunit/tests/user/capabilities.php b/tests/phpunit/tests/user/capabilities.php
index 87e498b..85fbf16 100644
--- a/tests/phpunit/tests/user/capabilities.php
+++ b/tests/phpunit/tests/user/capabilities.php
@@ -772,23 +772,59 @@ function test_post_meta_caps() {
 			$this->assertTrue( $admin->has_cap('add_post_meta',  $post) );
 			$this->assertTrue( $admin->has_cap('delete_post_meta',  $post) );

+			// Test protected key access is false
 			$this->assertFalse( $admin->has_cap('edit_post_meta', $post, '_protected') );
 			$this->assertFalse( $admin->has_cap('add_post_meta', $post, '_protected') );
 			$this->assertFalse( $admin->has_cap('delete_post_meta', $post, '_protected') );

-			register_meta( 'post', '_protected', array( $this, '_meta_filter' ), array( $this, '_meta_yes_you_can' ) );
+			// Register protected key and allow access
+			register_meta( 'post', '_protected', array( 'sanitize_callback' => array( $this, '_meta_filter' ), 'auth_callback' => array( $this, '_meta_yes_you_can' ) ) );
+
+			// Test protected key access is now true
 			$this->assertTrue( $admin->has_cap('edit_post_meta',  $post, '_protected') );
 			$this->assertTrue( $admin->has_cap('add_post_meta',  $post, '_protected') );
 			$this->assertTrue( $admin->has_cap('delete_post_meta',  $post, '_protected') );

+			// Test non protected key access is true
 			$this->assertTrue( $admin->has_cap('edit_post_meta', $post, 'not_protected') );
 			$this->assertTrue( $admin->has_cap('add_post_meta', $post, 'not_protected') );
 			$this->assertTrue( $admin->has_cap('delete_post_meta', $post, 'not_protected') );

-			register_meta( 'post', 'not_protected', array( $this, '_meta_filter' ), array( $this, '_meta_no_you_cant' ) );
+			// Register non protected key and disallow access
+			register_meta( 'post', 'not_protected', array( 'sanitize_callback' => array( $this, '_meta_filter' ), 'auth_callback' => array( $this, '_meta_no_you_cant' ) ) );
+
+			// Test non protected key access is now false
 			$this->assertFalse( $admin->has_cap('edit_post_meta',  $post, 'not_protected') );
 			$this->assertFalse( $admin->has_cap('add_post_meta',  $post, 'not_protected') );
 			$this->assertFalse( $admin->has_cap('delete_post_meta',  $post, 'not_protected') );
+
+			// Backwards compatibility tests for register_meta()
+
+			// Test protected key access is false
+			$this->assertFalse( $admin->has_cap('edit_post_meta', $post, '_protected_backcompat') );
+			$this->assertFalse( $admin->has_cap('add_post_meta', $post, '_protected_backcompat') );
+			$this->assertFalse( $admin->has_cap('delete_post_meta', $post, '_protected_backcompat') );
+
+			// Register protected key and allow access
+			register_meta( 'post', '_protected_backcompat', array( $this, '_meta_filter' ), array( $this, '_meta_yes_you_can' ) );
+
+			// Test protected key access is now true
+			$this->assertTrue( $admin->has_cap('edit_post_meta',  $post, '_protected_backcompat') );
+			$this->assertTrue( $admin->has_cap('add_post_meta',  $post, '_protected_backcompat') );
+			$this->assertTrue( $admin->has_cap('delete_post_meta',  $post, '_protected_backcompat') );
+
+			// Test non protected key access is true
+			$this->assertTrue( $admin->has_cap('edit_post_meta', $post, 'not_protected_backcompat') );
+			$this->assertTrue( $admin->has_cap('add_post_meta', $post, 'not_protected_backcompat') );
+			$this->assertTrue( $admin->has_cap('delete_post_meta', $post, 'not_protected_backcompat') );
+
+			// Register non protected key and disallow access
+			register_meta( 'post', 'not_protected_backcompat', array( $this, '_meta_filter' ), array( $this, '_meta_no_you_cant' ) );
+
+			// Test non protected key access is now false
+			$this->assertFalse( $admin->has_cap('edit_post_meta',  $post, 'not_protected_backcompat') );
+			$this->assertFalse( $admin->has_cap('add_post_meta',  $post, 'not_protected_backcompat') );
+			$this->assertFalse( $admin->has_cap('delete_post_meta',  $post, 'not_protected_backcompat') );
 		}
 	}

