diff --git src/wp-includes/user.php src/wp-includes/user.php
index 3c0f917bbc..c2d8970567 100644
--- src/wp-includes/user.php
+++ src/wp-includes/user.php
@@ -556,7 +556,24 @@ function count_user_posts( $userid, $post_type = 'post', $public_only = false )
 
 	$where = get_posts_by_author_sql( $post_type, true, $userid, $public_only );
 
-	$count = $wpdb->get_var( "SELECT COUNT(*) FROM $wpdb->posts $where" );
+	$post_type_label = $post_type;
+	if ( is_array( $post_type ) ) {
+		$post_type_label = implode( '_', $post_type );
+	}
+	$cache_key = "count_user_{$post_type_label}_{$userid}";
+
+	if ( $public_only ) {
+		$cache_group = 'user_posts_count_public';
+	} else {
+		$cache_group = 'user_posts_count';
+	}
+
+	$count = wp_cache_get( $cache_key, $cache_group );
+
+	if ( false === $count ) {
+		$count = $wpdb->get_var( "SELECT COUNT(*) FROM $wpdb->posts $where" );
+		wp_cache_add( $cache_key, $count, $cache_group );
+	}
 
 	/**
 	 * Filters the number of posts a user has written.
@@ -593,12 +610,8 @@ function count_many_users_posts( $users, $post_type = 'post', $public_only = fal
 		return $count;
 	}
 
-	$userlist = implode( ',', array_map( 'absint', $users ) );
-	$where    = get_posts_by_author_sql( $post_type, true, null, $public_only );
-
-	$result = $wpdb->get_results( "SELECT post_author, COUNT(*) FROM $wpdb->posts $where AND post_author IN ($userlist) GROUP BY post_author", ARRAY_N );
-	foreach ( $result as $row ) {
-		$count[ $row[0] ] = $row[1];
+	foreach ( $users as $user_id ) {
+		$count[ $user_id ] = count_user_posts( $user_id, $post_type, $public_only );
 	}
 
 	foreach ( $users as $id ) {
diff --git tests/phpunit/tests/user/countUserPosts.php tests/phpunit/tests/user/countUserPosts.php
index a4244e2814..991edc3b4f 100644
--- tests/phpunit/tests/user/countUserPosts.php
+++ tests/phpunit/tests/user/countUserPosts.php
@@ -89,4 +89,51 @@ class Tests_User_CountUserPosts extends WP_UnitTestCase {
 	public function test_count_user_posts_should_ignore_non_existent_post_types() {
 		$this->assertEquals( 4, count_user_posts( self::$user_id, array( 'foo', 'post' ) ) );
 	}
+
+	/**
+	 * Test the count_user_posts cache.
+	 *
+	 * @ticket 39242
+	 *
+	 * @dataProvider data_count_user_posts_cache
+	 *
+	 * Primarily, this tests that the cache is created when count_user_posts() is called.
+	 * Additionally, this tests using both a single post type string and an array of post types as a parameter.
+	 *
+	 * This ticket adds a cache key string to the function so we check that it is generated as exptected.
+	 *
+	 * @param string|array $post_type       Used to test the first param in count_user_posts().
+	 * @param string       $cache_key_lable Provides the expected cache key.
+	 */
+	public function test_count_user_posts_cache( $post_type, $cache_key_label) {
+		// Validate the cache is empty.
+		$cache = wp_cache_get( 'count_user_' . $cache_key_label . '_' . self::$user_id, 'user_posts_count' );
+		$this->assertFalse( $cache );
+
+		// Call the function.
+		$count = count_user_posts( self::$user_id, $post_type );
+
+		// Validate the cache is populated.
+		$cache = wp_cache_get( 'count_user_' . $cache_key_label . '_' . self::$user_id, 'user_posts_count' );
+		$this->assertEquals( $count, $cache );
+	}
+
+	/**
+	 * @ticket 39242
+	 */
+	public function data_count_user_posts_cache() {
+		return array (
+			array(
+				'post',
+				'post'
+			),
+			array(
+				array(
+					'post',
+					'wptests_pt',
+				),
+				'post_wptests_pt',
+			),
+		);
+	}
 }
