diff --git a/packages/block-editor/src/components/block-card/index.js b/packages/block-editor/src/components/block-card/index.js
index aaff1af27e16dd..df76c373642bc2 100644
--- a/packages/block-editor/src/components/block-card/index.js
+++ b/packages/block-editor/src/components/block-card/index.js
@@ -3,16 +3,18 @@
  */
 import BlockIcon from '../block-icon';
 
-function BlockCard( { blockType } ) {
+function BlockCard( { blockType, createdFromVariation } ) {
+	const title = createdFromVariation?.title || blockType.title;
+	const icon = createdFromVariation?.icon || blockType.icon;
+	const description =
+		createdFromVariation?.description || blockType.description;
 	return (
 		<div className="block-editor-block-card">
-			<BlockIcon icon={ blockType.icon } showColors />
+			<BlockIcon icon={ icon } showColors />
 			<div className="block-editor-block-card__content">
-				<h2 className="block-editor-block-card__title">
-					{ blockType.title }
-				</h2>
+				<h2 className="block-editor-block-card__title">{ title }</h2>
 				<span className="block-editor-block-card__description">
-					{ blockType.description }
+					{ description }
 				</span>
 			</div>
 		</div>
diff --git a/packages/block-editor/src/components/block-inspector/index.js b/packages/block-editor/src/components/block-inspector/index.js
index 259f4742febcd1..da43e3de2e119f 100644
--- a/packages/block-editor/src/components/block-inspector/index.js
+++ b/packages/block-editor/src/components/block-inspector/index.js
@@ -28,6 +28,7 @@ const BlockInspector = ( {
 	count,
 	hasBlockStyles,
 	selectedBlockClientId,
+	createdFromVariation,
 	selectedBlockName,
 	showNoBlockSelectedMessage = true,
 	bubblesVirtually = true,
@@ -65,7 +66,10 @@ const BlockInspector = ( {
 
 	return (
 		<div className="block-editor-block-inspector">
-			<BlockCard blockType={ blockType } />
+			<BlockCard
+				blockType={ blockType }
+				createdFromVariation={ createdFromVariation }
+			/>
 			{ hasBlockStyles && (
 				<div>
 					<PanelBody title={ __( 'Styles' ) }>
@@ -114,24 +118,28 @@ const AdvancedControls = ( { slotName, bubblesVirtually } ) => {
 };
 
 export default withSelect( ( select ) => {
-	const {
-		getSelectedBlockClientId,
-		getSelectedBlockCount,
-		getBlockName,
-	} = select( 'core/block-editor' );
+	const { getSelectedBlock, getSelectedBlockCount } = select(
+		'core/block-editor'
+	);
 	const { getBlockStyles } = select( 'core/blocks' );
-	const selectedBlockClientId = getSelectedBlockClientId();
-	const selectedBlockName =
-		selectedBlockClientId && getBlockName( selectedBlockClientId );
+	const selectedBlock = getSelectedBlock();
+	const selectedBlockClientId = selectedBlock?.clientId;
+	const selectedBlockName = selectedBlock?.name;
 	const blockType =
 		selectedBlockClientId && getBlockType( selectedBlockName );
 	const blockStyles =
 		selectedBlockClientId && getBlockStyles( selectedBlockName );
+	const createdFromVariation =
+		selectedBlock?.attributes?.fromVariation &&
+		blockType.variations?.find(
+			( { name } ) => name === selectedBlock.attributes.fromVariation
+		);
 	return {
 		count: getSelectedBlockCount(),
 		hasBlockStyles: blockStyles && blockStyles.length > 0,
 		selectedBlockName,
 		selectedBlockClientId,
 		blockType,
+		createdFromVariation,
 	};
 } )( BlockInspector );
diff --git a/packages/block-editor/src/components/block-switcher/index.js b/packages/block-editor/src/components/block-switcher/index.js
index 6f77c5ccf8be3e..6af575caf8565f 100644
--- a/packages/block-editor/src/components/block-switcher/index.js
+++ b/packages/block-editor/src/components/block-switcher/index.js
@@ -1,7 +1,7 @@
 /**
  * External dependencies
  */
-import { castArray, filter, mapKeys, orderBy, uniq, map } from 'lodash';
+import { castArray, filter, mapKeys, orderBy } from 'lodash';
 
 /**
  * WordPress dependencies
@@ -114,17 +114,30 @@ export class BlockSwitcher extends Component {
 
 		// When selection consists of blocks of multiple types, display an
 		// appropriate icon to communicate the non-uniformity.
-		const isSelectionOfSameType =
-			uniq( map( blocks, 'name' ) ).length === 1;
-
-		let icon;
-		if ( isSelectionOfSameType ) {
+		// If blocks are of same type and variation show variation's icon.
+		const getIcon = () => {
 			const sourceBlockName = hoveredBlock.name;
+			const isSelectionOfSameType = blocks.every(
+				( { name } ) => name === sourceBlockName
+			);
+			if ( ! isSelectionOfSameType ) return stack;
 			const blockType = getBlockType( sourceBlockName );
-			icon = blockType.icon;
-		} else {
-			icon = stack;
-		}
+			const isSelectionOfSameVariation = blocks.every(
+				( { attributes: { fromVariation } } ) =>
+					fromVariation &&
+					fromVariation === hoveredBlock.attributes.fromVariation
+			);
+			return (
+				( isSelectionOfSameVariation &&
+					blockType.variations?.find(
+						( { name } ) =>
+							hoveredBlock.attributes.fromVariation === name
+					)?.icon ) ||
+				blockType.icon
+			);
+		};
+
+		const icon = getIcon();
 
 		const hasPossibleBlockTransformations = !! possibleBlockTransformations.length;
 
diff --git a/packages/block-editor/src/store/selectors.js b/packages/block-editor/src/store/selectors.js
index 7185bc6f6c460d..68638ea5114170 100644
--- a/packages/block-editor/src/store/selectors.js
+++ b/packages/block-editor/src/store/selectors.js
@@ -1388,6 +1388,7 @@ const getItemFromVariation = ( item ) => ( variation ) => ( {
 	initialAttributes: {
 		...item.initialAttributes,
 		...variation.attributes,
+		fromVariation: variation.name,
 	},
 	innerBlocks: variation.innerBlocks,
 	keywords: variation.keywords || item.keywords,
diff --git a/packages/blocks/src/api/registration.js b/packages/blocks/src/api/registration.js
index 9052c76faf6948..677fe04724ff22 100644
--- a/packages/blocks/src/api/registration.js
+++ b/packages/blocks/src/api/registration.js
@@ -192,7 +192,7 @@ export function registerBlockType( name, settings ) {
 		return;
 	}
 	if ( select( 'core/blocks' ).getBlockType( name ) ) {
-		console.error( 'Block "' + name + '" is already registered.' );
+		console.error( `Block "${ name }" is already registered.` );
 		return;
 	}
 
@@ -247,17 +247,13 @@ export function registerBlockType( name, settings ) {
 		} )
 	) {
 		console.warn(
-			'The block "' +
-				name +
-				'" is registered with an invalid category "' +
-				settings.category +
-				'".'
+			`The block "${ name }" is registered with an invalid category "${ settings.category }".`
 		);
 		delete settings.category;
 	}
 
 	if ( ! ( 'title' in settings ) || settings.title === '' ) {
-		console.error( 'The block "' + name + '" must have a title.' );
+		console.error( `The block "${ name }" must have a title.` );
 		return;
 	}
 	if ( typeof settings.title !== 'string' ) {
@@ -265,6 +261,10 @@ export function registerBlockType( name, settings ) {
 		return;
 	}
 
+	if ( settings.variations?.length ) {
+		settings.attributes.fromVariation = { type: 'string' };
+	}
+
 	settings.icon = normalizeIconObject( settings.icon );
 	if ( ! isValidIcon( settings.icon.src ) ) {
 		console.error(