Index: src/wp-admin/network/themes.php
===================================================================
--- src/wp-admin/network/themes.php	(revision 36371)
+++ src/wp-admin/network/themes.php	(working copy)
@@ -29,12 +29,10 @@
 $referer = remove_query_arg( $temp_args, wp_get_referer() );
 
 if ( $action ) {
-	$allowed_themes = get_site_option( 'allowedthemes' );
 	switch ( $action ) {
 		case 'enable':
 			check_admin_referer('enable-theme_' . $_GET['theme']);
-			$allowed_themes[ $_GET['theme'] ] = true;
-			update_site_option( 'allowedthemes', $allowed_themes );
+			WP_Theme::network_enable_theme( $_GET['theme'] );
 			if ( false === strpos( $referer, '/network/themes.php' ) )
 				wp_redirect( network_admin_url( 'themes.php?enabled=1' ) );
 			else
@@ -42,8 +40,7 @@
 			exit;
 		case 'disable':
 			check_admin_referer('disable-theme_' . $_GET['theme']);
-			unset( $allowed_themes[ $_GET['theme'] ] );
-			update_site_option( 'allowedthemes', $allowed_themes );
+			WP_Theme::network_disable_theme( $_GET['theme'] );
 			wp_safe_redirect( add_query_arg( 'disabled', '1', $referer ) );
 			exit;
 		case 'enable-selected':
@@ -53,9 +50,7 @@
 				wp_safe_redirect( add_query_arg( 'error', 'none', $referer ) );
 				exit;
 			}
-			foreach ( (array) $themes as $theme )
-				$allowed_themes[ $theme ] = true;
-			update_site_option( 'allowedthemes', $allowed_themes );
+			WP_Theme::network_enable_theme( (array) $themes );
 			wp_safe_redirect( add_query_arg( 'enabled', count( $themes ), $referer ) );
 			exit;
 		case 'disable-selected':
@@ -65,9 +60,7 @@
 				wp_safe_redirect( add_query_arg( 'error', 'none', $referer ) );
 				exit;
 			}
-			foreach ( (array) $themes as $theme )
-				unset( $allowed_themes[ $theme ] );
-			update_site_option( 'allowedthemes', $allowed_themes );
+			WP_Theme::network_disable_theme( (array) $themes );
 			wp_safe_redirect( add_query_arg( 'disabled', count( $themes ), $referer ) );
 			exit;
 		case 'update-selected' :
Index: src/wp-includes/class-wp-theme.php
===================================================================
--- src/wp-includes/class-wp-theme.php	(revision 36371)
+++ src/wp-includes/class-wp-theme.php	(working copy)
@@ -1308,6 +1308,54 @@
 	}
 
 	/**
+	 * Enable a theme for a whole network
+	 *
+	 * @since 4.5
+	 *
+	 * @static
+	 * @access public
+	 *
+	 * @param string|array $stylesheets Stylesheet name or array of stylesheets
+	 */
+	public static function network_enable_theme( $stylesheets ) {
+	    if ( ! is_array( $stylesheets ) ) {
+		    $stylesheets = array( $stylesheets );
+	    }
+
+	    $allowed_themes = get_site_option( 'allowedthemes' );
+	    foreach ( $stylesheets as $stylesheet ) {
+		    $allowed_themes[ $stylesheet ] = true;
+	    }
+
+	    update_site_option( 'allowedthemes', $allowed_themes );
+    }
+
+	/**
+	 * Disable a theme for a whole network
+	 *
+	 * @since 4.5
+	 *
+	 * @static
+	 * @access public
+	 *
+	 * @param string|array $stylesheets Stylesheet name or array of stylesheets
+	 */
+	public static function network_disable_theme( $stylesheets ) {
+        if ( ! is_array( $stylesheets ) ) {
+	        $stylesheets = array( $stylesheets );
+        }
+
+        $allowed_themes = get_site_option( 'allowedthemes' );
+        foreach ( $stylesheets as $stylesheet ) {
+	        if ( isset( $allowed_themes[ $stylesheet ] ) ) {
+		        unset( $allowed_themes[ $stylesheet ] );
+	        }
+        }
+
+        update_site_option( 'allowedthemes', $allowed_themes );
+    }
+
+	/**
 	 * Sort themes by name.
 	 *
 	 * @since 3.4.0
Index: tests/phpunit/tests/multisite/network.php
===================================================================
--- tests/phpunit/tests/multisite/network.php	(revision 36371)
+++ tests/phpunit/tests/multisite/network.php	(working copy)
@@ -249,6 +249,108 @@
 		$dashboard_blog = get_dashboard_blog();
 		$this->assertEquals( $blog_id, $dashboard_blog->blog_id );
 	}
+
+	/**
+	 * Network enable one theme
+	 *
+	 * @ticket 30594
+	 */
+	function test_network_enable_theme() {
+		$theme = 'testtheme-1';
+		WP_Theme::network_enable_theme( $theme );
+		$enabled = get_site_option( 'allowedthemes' );
+		$this->assertArrayHasKey( 'testtheme-1', $enabled );
+
+		// Enable again
+		WP_Theme::network_enable_theme( $theme );
+		$enabled = get_site_option( 'allowedthemes' );
+		$this->assertArrayHasKey( 'testtheme-1', $enabled );
+	}
+
+	/**
+	 * Network enable a few themes
+	 *
+	 * @ticket 30594
+	 */
+	function test_network_enable_themes() {
+		// Enable one
+		WP_Theme::network_enable_theme( array( 'testtheme-1' ) );
+
+		// Now enable the rest
+		$themes = array( 'testtheme-2', 'testtheme-3' );
+		WP_Theme::network_enable_theme( $themes );
+		$enabled = get_site_option( 'allowedthemes' );
+		$this->assertArrayHasKey( 'testtheme-1', $enabled );
+		$this->assertArrayHasKey( 'testtheme-2', $enabled );
+		$this->assertArrayHasKey( 'testtheme-3', $enabled );
+
+		// Enable again
+		WP_Theme::network_enable_theme( $themes );
+		$enabled = get_site_option( 'allowedthemes' );
+		$this->assertArrayHasKey( 'testtheme-1', $enabled );
+		$this->assertArrayHasKey( 'testtheme-2', $enabled );
+		$this->assertArrayHasKey( 'testtheme-3', $enabled );
+
+	}
+
+	/**
+	 * Network disable one theme
+	 *
+	 * @ticket 30594
+	 */
+	function test_network_disable_theme() {
+		// First, enable a few themes
+		$themes = array( 'testtheme-1', 'testtheme-2', 'testtheme-3', 'testtheme-4' );
+		WP_Theme::network_enable_theme( $themes );
+
+		// Disable one only theme
+		WP_Theme::network_disable_theme( 'testtheme-2' );
+		$enabled = get_site_option( 'allowedthemes' );
+
+		$this->assertArrayHasKey( 'testtheme-1', $enabled );
+		$this->assertArrayHasKey( 'testtheme-3', $enabled );
+		$this->assertArrayHasKey( 'testtheme-4', $enabled );
+		$this->assertFalse( isset( $enabled['testtheme-2'] ) );
+
+		// And disable again
+		WP_Theme::network_disable_theme( 'testtheme-2' );
+		$enabled = get_site_option( 'allowedthemes' );
+		$this->assertArrayHasKey( 'testtheme-1', $enabled );
+		$this->assertArrayHasKey( 'testtheme-3', $enabled );
+		$this->assertArrayHasKey( 'testtheme-4', $enabled );
+		$this->assertFalse( isset( $enabled['testtheme-2'] ) );
+	}
+
+	/**
+	 * Network disable a few themes
+	 *
+	 * @ticket 30594
+	 */
+	function test_network_disable_themes() {
+		// First, enable a few themes
+		$themes = array( 'testtheme-1', 'testtheme-2', 'testtheme-3', 'testtheme-4' );
+		WP_Theme::network_enable_theme( $themes );
+
+		// Disable one
+		WP_Theme::network_disable_theme( array( 'testtheme-2' ) );
+
+		// And disable the rest of themes
+		$remove = array( 'testtheme-1', 'testtheme-3' );
+		WP_Theme::network_disable_theme( $remove );
+		$enabled = get_site_option( 'allowedthemes' );
+		$this->assertArrayHasKey( 'testtheme-4', $enabled );
+		$this->assertFalse( isset( $enabled['testtheme-1'] ) );
+		$this->assertFalse( isset( $enabled['testtheme-2'] ) );
+		$this->assertFalse( isset( $enabled['testtheme-3'] ) );
+
+		// And disable again
+		WP_Theme::network_disable_theme( $remove );
+		$enabled = get_site_option( 'allowedthemes' );
+		$this->assertArrayHasKey( 'testtheme-4', $enabled );
+		$this->assertFalse( isset( $enabled['testtheme-1'] ) );
+		$this->assertFalse( isset( $enabled['testtheme-2'] ) );
+		$this->assertFalse( isset( $enabled['testtheme-3'] ) );
+	}
 }
 
 endif;
