diff --git src/wp-includes/capabilities.php src/wp-includes/capabilities.php
index 7c570c4..d8f52fe 100644
--- src/wp-includes/capabilities.php
+++ src/wp-includes/capabilities.php
@@ -16,6 +16,8 @@
  *
  * @since 2.0.0
  *
+ * @global array $post_type_meta_caps Used to get post type meta capabilities.
+ *
  * @param string $cap       Capability name.
  * @param int    $user_id   User ID.
  * @param int    $object_id Optional. ID of the specific object to check against if `$cap` is a "meta" cap.
@@ -377,7 +379,7 @@ function map_meta_cap( $cap, $user_id ) {
 		break;
 	default:
 		// Handle meta capabilities for custom post types.
-		$post_type_meta_caps = _post_type_meta_capabilities();
+		global $post_type_meta_caps;
 		if ( isset( $post_type_meta_caps[ $cap ] ) ) {
 			$args = array_merge( array( $post_type_meta_caps[ $cap ], $user_id ), $args );
 			return call_user_func_array( 'map_meta_cap', $args );
diff --git src/wp-includes/post.php src/wp-includes/post.php
index cc8e843..a3aefe8 100644
--- src/wp-includes/post.php
+++ src/wp-includes/post.php
@@ -1187,6 +1187,88 @@ function register_post_type( $post_type, $args = array() ) {
 }
 
 /**
+ * Unregister a post type.
+ *
+ * Can not be used to unregister built-in post types.
+ *
+ * @since 4.5.0
+ *
+ * @global WP_Rewrite $wp_rewrite             WordPress rewrite component.
+ * @global WP         $wp                     Current WordPress environment instance.
+ * @global array      $_wp_post_type_features Used to remove post type features.
+ * @global array      $post_type_meta_caps    Used to remove meta capabilities.
+ * @global array      $wp_post_types          List of post types.
+ *
+ * @param string $post_type Post type key.
+ * @return bool|WP_Error True on success, WP_Error on failure.
+ */
+function unregister_post_type( $post_type ) {
+	if ( ! post_type_exists( $post_type ) ) {
+		return new WP_Error( 'invalid_post_type', __( 'Invalid post type' ) );
+	}
+
+	$post_type_args = get_post_type_object( $post_type );
+
+	// Do not allow unregistering internal post types.
+	if ( $post_type_args->_builtin ) {
+		return new WP_Error( 'invalid_post_type', __( 'Unregistering a built-in post type is not allowed' ) );
+	}
+
+	global $wp, $wp_rewrite, $_wp_post_type_features, $post_type_meta_caps, $wp_post_types;
+
+	// Remove query var.
+	if ( false !== $post_type_args->query_var ) {
+		$wp->remove_query_var( $post_type_args->query_var );
+	}
+
+	// Remove any rewrite rules, permastructs, and rules.
+	if ( false !== $post_type_args->rewrite ) {
+		remove_rewrite_tag( "%$post_type%" );
+		remove_permastruct( $post_type );
+		foreach ( $wp_rewrite->extra_rules_top as $regex => $query ) {
+			if ( false !== strpos( $query, "index.php?post_type=$post_type" ) ) {
+				unset( $wp_rewrite->extra_rules_top[ $regex ] );
+			}
+		}
+	}
+
+	// Remove registered custom meta capabilities.
+	foreach ( $post_type_args->cap as $cap ) {
+		unset( $post_type_meta_caps[ $cap ] );
+	}
+
+	// Remove all post type support.
+	unset( $_wp_post_type_features[ $post_type ] );
+
+	// Unregister the post type meta box if a custom callback was specified.
+	if ( $post_type_args->register_meta_box_cb ) {
+		remove_action( 'add_meta_boxes_' . $post_type, $post_type_args->register_meta_box_cb );
+	}
+
+	// Remove the post type from all taxonomies.
+	foreach ( get_object_taxonomies( $post_type ) as $taxonomy ) {
+		unregister_taxonomy_for_object_type( $taxonomy, $post_type );
+	}
+
+	// Remove the future post hook action.
+	remove_action( 'future_' . $post_type, '_future_post_hook', 5 );
+
+	// Remove the post type.
+	unset( $wp_post_types[ $post_type ] );
+
+	/**
+	 * Fires after a post type was unregistered.
+	 *
+	 * @since 4.5.0
+	 *
+	 * @param string $post_type Post type key.
+	 */
+	do_action( 'unregistered_post_type', $post_type );
+
+	return true;
+}
+
+/**
  * Build an object with all post type capabilities out of a post type object
  *
  * Post type capabilities use the 'capability_type' argument as a base, if the
@@ -1293,17 +1375,17 @@ function get_post_type_capabilities( $args ) {
  * @since 3.1.0
  * @access private
  *
- * @staticvar array $meta_caps
+ * @global array $post_type_meta_caps Used to store meta capabilities.
  *
- * @param array|void $capabilities Post type meta capabilities.
+ * @param array $capabilities Post type meta capabilities.
  */
 function _post_type_meta_capabilities( $capabilities = null ) {
-	static $meta_caps = array();
-	if ( null === $capabilities )
-		return $meta_caps;
+	global $post_type_meta_caps;
+
 	foreach ( $capabilities as $core => $custom ) {
-		if ( in_array( $core, array( 'read_post', 'delete_post', 'edit_post' ) ) )
-			$meta_caps[ $custom ] = $core;
+		if ( in_array( $core, array( 'read_post', 'delete_post', 'edit_post' ) ) ) {
+			$post_type_meta_caps[ $custom ] = $core;
+		}
 	}
 }
 
diff --git tests/phpunit/includes/utils.php tests/phpunit/includes/utils.php
index 0a6dfc1..5d595d5 100644
--- tests/phpunit/includes/utils.php
+++ tests/phpunit/includes/utils.php
@@ -323,14 +323,7 @@ if ( !function_exists( 'str_getcsv' ) ) {
  * Removes the post type and its taxonomy associations.
  */
 function _unregister_post_type( $cpt_name ) {
-	unset( $GLOBALS['wp_post_types'][ $cpt_name ] );
-	unset( $GLOBALS['_wp_post_type_features'][ $cpt_name ] );
-
-	foreach ( $GLOBALS['wp_taxonomies'] as $taxonomy ) {
-		if ( false !== $key = array_search( $cpt_name, $taxonomy->object_type ) ) {
-			unset( $taxonomy->object_type[$key] );
-		}
-	}
+	unregister_post_type( $cpt_name );
 }
 
 function _unregister_taxonomy( $taxonomy_name ) {
@@ -398,7 +391,7 @@ class wpdb_exposed_methods_for_testing extends wpdb {
  */
 function benchmark_pcre_backtracking( $pattern, $subject, $strategy ) {
 	$saved_config = ini_get( 'pcre.backtrack_limit' );
-	
+
 	// Attempt to prevent PHP crashes.  Adjust these lower when needed.
 	if ( version_compare( phpversion(), '5.4.8', '>' ) ) {
 		$limit = 1000000;
@@ -410,7 +403,7 @@ function benchmark_pcre_backtracking( $pattern, $subject, $strategy ) {
 	for( $i = 4; $i <= $limit; $i *= 2 ) {
 
 		ini_set( 'pcre.backtrack_limit', $i );
-		
+
 		switch( $strategy ) {
 		case 'split':
 			preg_split( $pattern, $subject );
diff --git tests/phpunit/tests/post/types.php tests/phpunit/tests/post/types.php
index 02d4590..83b272c 100644
--- tests/phpunit/tests/post/types.php
+++ tests/phpunit/tests/post/types.php
@@ -20,7 +20,7 @@ class Tests_Post_Types extends WP_UnitTestCase {
 	}
 
 	/**
-	 * @ticket 31134
+	 * @ticket                 31134
 	 *
 	 * @expectedIncorrectUsage register_post_type
 	 */
@@ -30,7 +30,7 @@ class Tests_Post_Types extends WP_UnitTestCase {
 	}
 
 	/**
-	 * @ticket 31134
+	 * @ticket                 31134
 	 *
 	 * @expectedIncorrectUsage register_post_type
 	 */
@@ -119,6 +119,7 @@ class Tests_Post_Types extends WP_UnitTestCase {
 	public function filter_post_type_labels( $labels ) {
 		unset( $labels->featured_image );
 		unset( $labels->set_featured_image );
+
 		return $labels;
 	}
 
@@ -159,4 +160,204 @@ class Tests_Post_Types extends WP_UnitTestCase {
 
 		_unregister_post_type( 'foo' );
 	}
+
+	/**
+	 * @ticket 14761
+	 */
+	public function test_unregister_post_type() {
+		register_post_type( 'foo' );
+		$this->assertTrue( unregister_post_type( 'foo' ) );
+	}
+
+	/**
+	 * @ticket 14761
+	 */
+	public function test_unregister_post_type_unknown_post_type() {
+		$this->assertWPError( unregister_post_type( 'foo' ) );
+	}
+
+	/**
+	 * @ticket 14761
+	 */
+	public function test_unregister_post_type_twice() {
+		register_post_type( 'foo' );
+		$this->assertTrue( unregister_post_type( 'foo' ) );
+		$this->assertWPError( unregister_post_type( 'foo' ) );
+	}
+
+	/**
+	 * @ticket 14761
+	 */
+	public function test_unregister_post_type_disallow_builtin_post_type() {
+		$this->assertWPError( unregister_post_type( 'post' ) );
+		$this->assertWPError( unregister_post_type( 'page' ) );
+		$this->assertWPError( unregister_post_type( 'attachment' ) );
+		$this->assertWPError( unregister_post_type( 'revision' ) );
+		$this->assertWPError( unregister_post_type( 'nav_menu_item' ) );
+	}
+
+	/**
+	 * @ticket 14761
+	 */
+	public function test_unregister_post_type_removes_query_vars() {
+		global $wp;
+
+		register_post_type( 'foo', array(
+			'public'    => true,
+			'query_var' => 'bar',
+		) );
+
+		$this->assertInternalType( 'int', array_search( 'bar', $wp->public_query_vars ) );
+		$this->assertTrue( unregister_post_type( 'foo' ) );
+		$this->assertFalse( array_search( 'bar', $wp->public_query_vars ) );
+	}
+
+	/**
+	 * @ticket 14761
+	 */
+	public function test_unregister_post_type_removes_rewrite_tags() {
+		$this->set_permalink_structure( '/%postname%' );
+
+		global $wp_rewrite;
+
+		register_post_type( 'foo', array(
+			'public'    => true,
+			'query_var' => 'bar',
+		) );
+
+		$count_before = count( $wp_rewrite->rewritereplace );
+
+		$this->assertContains( '%foo%', $wp_rewrite->rewritecode );
+		$this->assertContains( 'bar=', $wp_rewrite->queryreplace );
+		$this->assertTrue( unregister_post_type( 'foo' ) );
+		$this->assertNotContains( '%foo%', $wp_rewrite->rewritecode );
+		$this->assertNotContains( 'bar=', $wp_rewrite->queryreplace );
+		$this->assertSame( -- $count_before, count( $wp_rewrite->rewritereplace ) ); // Array was reduced by one value.
+	}
+
+	/**
+	 * @ticket 14761
+	 */
+	public function test_unregister_post_type_removes_rewrite_rules() {
+		$this->set_permalink_structure( '/%postname%' );
+
+		global $wp_rewrite;
+
+		register_post_type( 'foo', array(
+			'public'      => true,
+			'has_archive' => true,
+		) );
+
+		$this->assertContains( 'index.php?post_type=foo', $wp_rewrite->extra_rules_top );
+		$this->assertTrue( unregister_post_type( 'foo' ) );
+		$this->assertNotContains( 'index.php?post_type=foo', $wp_rewrite->extra_rules_top );
+	}
+
+	/**
+	 * @ticket 14761
+	 */
+	public function test_unregister_post_type_removes_custom_meta_capabilities() {
+		global $post_type_meta_caps;
+
+		register_post_type( 'foo', array(
+			'public'          => true,
+			'capability_type' => 'bar',
+			'map_meta_cap' => true,
+		) );
+
+		$this->assertSame( 'read_post', $post_type_meta_caps['read_bar'] );
+		$this->assertSame( 'delete_post', $post_type_meta_caps['delete_bar'] );
+		$this->assertSame( 'edit_post', $post_type_meta_caps['edit_bar'] );
+
+		$this->assertTrue( unregister_post_type( 'foo' ) );
+
+		$this->assertFalse( isset( $post_type_meta_caps['read_bar'] ) );
+		$this->assertFalse( isset( $post_type_meta_caps['delete_bar'] ) );
+		$this->assertFalse( isset( $post_type_meta_caps['edit_bar'] ) );
+	}
+
+	/**
+	 * @ticket 14761
+	 */
+	public function test_unregister_post_type_removes_post_type_supports() {
+		global $_wp_post_type_features;
+
+		register_post_type( 'foo', array(
+			'public'   => true,
+			'supports' => array( 'editor', 'author', 'title' ),
+		) );
+
+		$this->assertEqualSetsWithIndex( array( 'editor' => true, 'author' => true, 'title' => true ), $_wp_post_type_features['foo'] );
+		$this->assertTrue( unregister_post_type( 'foo' ) );
+		$this->assertFalse( isset( $_wp_post_type_features['foo'] ) );
+	}
+
+	/**
+	 * @ticket 14761
+	 */
+	public function test_unregister_post_type_removes_post_type_from_taxonomies() {
+		global $wp_taxonomies;
+
+		register_post_type( 'foo', array(
+			'public'     => true,
+			'taxonomies' => array( 'category', 'post_tag' ),
+		) );
+
+		$this->assertInternalType( 'int', array_search( 'foo', $wp_taxonomies['category']->object_type, true ) );
+		$this->assertInternalType( 'int', array_search( 'foo', $wp_taxonomies['post_tag']->object_type, true ) );
+		$this->assertTrue( unregister_post_type( 'foo' ) );
+		$this->assertFalse( array_search( 'foo', $wp_taxonomies['category']->object_type, true ) );
+		$this->assertFalse( array_search( 'foo', $wp_taxonomies['post_tag']->object_type, true ) );
+		$this->assertEmpty( get_object_taxonomies( 'foo' ) );
+	}
+
+	/**
+	 * @ticket 14761
+	 */
+	public function test_unregister_post_type_removes_the_future_post_hooks() {
+		global $wp_filter;
+
+		register_post_type( 'foo', array(
+			'public' => true,
+		) );
+
+		$this->assertSame( 1, count( $wp_filter['future_foo'] ) );
+		$this->assertTrue( unregister_post_type( 'foo' ) );
+		$this->assertSame( array(), $wp_filter['future_foo'] );
+	}
+
+	/**
+	 * @ticket 14761
+	 */
+	public function test_unregister_post_type_removes_meta_box_callback() {
+		global $wp_filter;
+
+		register_post_type( 'foo', array(
+			'public'               => true,
+			'register_meta_box_cb' => '__return_empty_string',
+		) );
+
+		$this->assertSame( 1, count( $wp_filter['add_meta_boxes_foo'] ) );
+		$this->assertTrue( unregister_post_type( 'foo' ) );
+		$this->assertSame( array(), $wp_filter['add_meta_boxes_foo'] );
+	}
+
+	/**
+	 * @ticket 14761
+	 */
+	public function test_unregister_post_type_removes_post_type_from_global() {
+		global $wp_post_types;
+
+		register_post_type( 'foo', array(
+			'public' => true,
+		) );
+
+		$this->assertInternalType( 'object', $wp_post_types['foo'] );
+		$this->assertInternalType( 'object', get_post_type_object( 'foo' ) );
+
+		$this->assertTrue( unregister_post_type( 'foo' ) );
+
+		$this->assertFalse( isset( $wp_post_types['foo'] ) );
+		$this->assertNull( get_post_type_object( 'foo' ) );
+	}
 }
