Index: src/Concurrency/Keywords.cc
===================================================================
--- src/Concurrency/Keywords.cc	(revision cd59d28d0ab3255be07ca6dffc9b4f03bd059efd)
+++ src/Concurrency/Keywords.cc	(revision ecfd7589e4796949fcc35b475a024d4acda6e636)
@@ -42,6 +42,9 @@
 
 namespace Concurrency {
+	inline static std::string getTypeIdName( std::string const & exception_name ) {
+		return exception_name.empty() ? std::string() : Virtual::typeIdType( exception_name );
+	}
 	inline static std::string getVTableName( std::string const & exception_name ) {
-		return exception_name.empty() ? std::string() : Virtual::vtableTypeName(exception_name);
+		return exception_name.empty() ? std::string() : Virtual::vtableTypeName( exception_name );
 	}
 
@@ -75,4 +78,5 @@
 		  type_name( type_name ), field_name( field_name ), getter_name( getter_name ),
 		  context_error( context_error ), exception_name( exception_name ),
+		  typeid_name( getTypeIdName( exception_name ) ),
 		  vtable_name( getVTableName( exception_name ) ),
 		  needs_main( needs_main ), cast_target( cast_target ) {}
@@ -84,4 +88,5 @@
 
 		void handle( StructDecl * );
+		void addTypeId( StructDecl * );
 		void addVtableForward( StructDecl * );
 		FunctionDecl * forwardDeclare( StructDecl * );
@@ -99,4 +104,5 @@
 		const std::string context_error;
 		const std::string exception_name;
+		const std::string typeid_name;
 		const std::string vtable_name;
 		bool needs_main;
@@ -106,4 +112,5 @@
 		FunctionDecl * dtor_decl = nullptr;
 		StructDecl * except_decl = nullptr;
+		StructDecl * typeid_decl = nullptr;
 		StructDecl * vtable_decl = nullptr;
 	};
@@ -392,4 +399,7 @@
 		else if ( !except_decl && exception_name == decl->name && decl->body ) {
 			except_decl = decl;
+		}
+		else if ( !typeid_decl && typeid_name == decl->name && decl->body ) {
+			typeid_decl = decl;
 		}
 		else if ( !vtable_decl && vtable_name == decl->name && decl->body ) {
@@ -448,5 +458,11 @@
 		if( !dtor_decl ) SemanticError( decl, context_error );
 
-		addVtableForward( decl );
+		if ( !exception_name.empty() ) {
+			if( !typeid_decl ) SemanticError( decl, context_error );
+			if( !vtable_decl ) SemanticError( decl, context_error );
+
+			addTypeId( decl );
+			addVtableForward( decl );
+		}
 		FunctionDecl * func = forwardDeclare( decl );
 		ObjectDecl * field = addField( decl );
@@ -454,19 +470,24 @@
 	}
 
+	void ConcurrentSueKeyword::addTypeId( StructDecl * decl ) {
+		assert( typeid_decl );
+		StructInstType typeid_type( Type::Const, typeid_decl );
+		typeid_type.parameters.push_back( new TypeExpr(
+			new StructInstType( noQualifiers, decl )
+			) );
+		declsToAddBefore.push_back( Virtual::makeTypeIdInstance( &typeid_type ) );
+	}
+
 	void ConcurrentSueKeyword::addVtableForward( StructDecl * decl ) {
-		if ( vtable_decl ) {
-			std::list< Expression * > poly_args = {
-				new TypeExpr( new StructInstType( noQualifiers, decl ) ),
-			};
-			declsToAddBefore.push_back( Virtual::makeGetExceptionForward(
-				vtable_decl->makeInst( poly_args ),
-				except_decl->makeInst( poly_args )
-			) );
-			declsToAddBefore.push_back( Virtual::makeVtableForward(
-				vtable_decl->makeInst( move( poly_args ) ) ) );
-		// Its only an error if we want a vtable and don't have one.
-		} else if ( ! vtable_name.empty() ) {
-			SemanticError( decl, context_error );
-		}
+		assert( vtable_decl );
+		std::list< Expression * > poly_args = {
+			new TypeExpr( new StructInstType( noQualifiers, decl ) ),
+		};
+		declsToAddBefore.push_back( Virtual::makeGetExceptionForward(
+			vtable_decl->makeInst( poly_args ),
+			except_decl->makeInst( poly_args )
+		) );
+		declsToAddBefore.push_back( Virtual::makeVtableForward(
+			vtable_decl->makeInst( move( poly_args ) ) ) );
 	}
 
Index: src/Virtual/ExpandCasts.cc
===================================================================
--- src/Virtual/ExpandCasts.cc	(revision cd59d28d0ab3255be07ca6dffc9b4f03bd059efd)
+++ src/Virtual/ExpandCasts.cc	(revision ecfd7589e4796949fcc35b475a024d4acda6e636)
@@ -32,4 +32,14 @@
 namespace Virtual {
 
+static bool is_prefix( const std::string & prefix, const std::string& entire ) {
+	size_t const p_size = prefix.size();
+	return (p_size < entire.size() && prefix == entire.substr(0, p_size));
+}
+
+static bool is_type_id_object( const ObjectDecl * objectDecl ) {
+	const std::string & objectName = objectDecl->name;
+	return is_prefix( "__cfatid_", objectName );
+}
+
 	// Indented until the new ast code gets added.
 
@@ -66,36 +76,4 @@
 	};
 
-	/* Currently virtual depends on the rather brittle name matching between
-	 * a (strict/explicate) virtual type, its vtable type and the vtable
-	 * instance.
-	 * A stronger implementation, would probably keep track of those triads
-	 * and use that information to create better error messages.
-	 */
-
-	namespace {
-
-	std::string get_vtable_name( std::string const & name ) {
-		return name + "_vtable";
-	}
-
-	std::string get_vtable_inst_name( std::string const & name ) {
-		return std::string("_") + get_vtable_name( name ) + "_instance";
-	}
-
-	std::string get_vtable_name_root( std::string const & name ) {
-		return name.substr(0, name.size() - 7 );
-	}
-
-	std::string get_vtable_inst_name_root( std::string const & name ) {
-		return get_vtable_name_root( name.substr(1, name.size() - 10 ) );
-	}
-
-	bool is_vtable_inst_name( std::string const & name ) {
-		return 17 < name.size() &&
-			name == get_vtable_inst_name( get_vtable_inst_name_root( name ) );
-	}
-
-	} // namespace
-
 	class VirtualCastCore {
 		Type * pointer_to_pvt(int level_of_indirection) {
@@ -141,11 +119,7 @@
 
 	void VirtualCastCore::premutate( ObjectDecl * objectDecl ) {
-		if ( is_vtable_inst_name( objectDecl->get_name() ) ) {
-			if ( ObjectDecl * existing = indexer.insert( objectDecl ) ) {
-				std::string msg = "Repeated instance of virtual table, original found at: ";
-				msg += existing->location.filename;
-				msg += ":" + toString( existing->location.first_line );
-				SemanticError( objectDecl->location, msg );
-			}
+		if ( is_type_id_object( objectDecl ) ) {
+			// Multiple definitions should be fine because of linkonce.
+			indexer.insert( objectDecl );
 		}
 	}
@@ -170,52 +144,87 @@
 	}
 
-	/// Get the virtual table type used in a virtual cast.
-	Type * getVirtualTableType( const VirtualCastExpr * castExpr ) {
-		const Type * objectType;
-		if ( auto target = dynamic_cast<const PointerType *>( castExpr->result ) ) {
-			objectType = target->base;
-		} else if ( auto target = dynamic_cast<const ReferenceType *>( castExpr->result ) ) {
-			objectType = target->base;
+	/// Get the base type from a pointer or reference.
+	const Type * getBaseType( const Type * type ) {
+		if ( auto target = dynamic_cast<const PointerType *>( type ) ) {
+			return target->base;
+		} else if ( auto target = dynamic_cast<const ReferenceType *>( type ) ) {
+			return target->base;
 		} else {
-			castError( castExpr, "Virtual cast type must be a pointer or reference type." );
-		}
-		assert( objectType );
-
-		const StructInstType * structType = dynamic_cast<const StructInstType *>( objectType );
-		if ( nullptr == structType ) {
-			castError( castExpr, "Virtual cast type must refer to a structure type." );
-		}
-		const StructDecl * structDecl = structType->baseStruct;
-		assert( structDecl );
-
-		const ObjectDecl * fieldDecl = nullptr;
-		if ( 0 < structDecl->members.size() ) {
-			const Declaration * memberDecl = structDecl->members.front();
+			return nullptr;
+		}
+	}
+
+	/* Attempt to follow the "head" field of the structure to get the...
+	 * Returns nullptr on error, otherwise owner must free returned node.
+	 */
+	StructInstType * followHeadPointerType(
+			const StructInstType * oldType,
+			const std::string& fieldName,
+			const CodeLocation& errorLocation ) {
+
+		// First section of the function is all about trying to fill this variable in.
+		StructInstType * newType = nullptr;
+		{
+			const StructDecl * oldDecl = oldType->baseStruct;
+			assert( oldDecl );
+
+			// Helper function for throwing semantic errors.
+			auto throwError = [&fieldName, &errorLocation, &oldDecl](const std::string& message) {
+				const std::string& context = "While following head pointer of " +
+					oldDecl->name + " named '" + fieldName + "': ";
+				SemanticError( errorLocation, context + message );
+			};
+
+			if ( oldDecl->members.empty() ) {
+				throwError( "Type has no fields." );
+			}
+			const Declaration * memberDecl = oldDecl->members.front();
 			assert( memberDecl );
-			fieldDecl = dynamic_cast<const ObjectDecl *>( memberDecl );
-			if ( fieldDecl && fieldDecl->name != "virtual_table" ) {
-				fieldDecl = nullptr;
-			}
-		}
-		if ( nullptr == fieldDecl ) {
-			castError( castExpr, "Virtual cast type must have a leading virtual_table field." );
-		}
-		const PointerType * fieldType = dynamic_cast<const PointerType *>( fieldDecl->type );
-		if ( nullptr == fieldType ) {
-			castError( castExpr, "Virtual cast type virtual_table field is not a pointer." );
-		}
-		assert( fieldType->base );
-		auto virtualStructType = dynamic_cast<const StructInstType *>( fieldType->base );
-		assert( virtualStructType );
-
-		// Here is the type, but if it is polymorphic it will have lost information.
-		// (Always a clone so that it may always be deleted.)
-		StructInstType * virtualType = virtualStructType->clone();
-		if ( ! structType->parameters.empty() ) {
-			deleteAll( virtualType->parameters );
-			virtualType->parameters.clear();
-			cloneAll( structType->parameters, virtualType->parameters );
-		}
-		return virtualType;
+			const ObjectDecl * fieldDecl = dynamic_cast<const ObjectDecl *>( memberDecl );
+			assert( fieldDecl );
+			if ( fieldName != fieldDecl->name ) {
+				throwError( "Head field did not have expected name." );
+			}
+
+			const Type * fieldType = fieldDecl->type;
+			if ( nullptr == fieldType ) {
+				throwError( "Could not get head field." );
+			}
+			const PointerType * ptrType = dynamic_cast<const PointerType *>( fieldType );
+			if ( nullptr == ptrType ) {
+				throwError( "First field is not a pointer type." );
+			}
+			assert( ptrType->base );
+			newType = dynamic_cast<StructInstType *>( ptrType->base );
+			if ( nullptr == newType ) {
+				throwError( "First field does not point to a structure type." );
+			}
+		}
+
+		// Now we can look into copying it.
+		newType = newType->clone();
+		if ( ! oldType->parameters.empty() ) {
+			deleteAll( newType->parameters );
+			newType->parameters.clear();
+			cloneAll( oldType->parameters, newType->parameters );
+		}
+		return newType;
+	}
+
+	/// Get the type-id type from a virtual type.
+	StructInstType * getTypeIdType( const Type * type, const CodeLocation& errorLocation ) {
+		const StructInstType * typeInst = dynamic_cast<const StructInstType *>( type );
+		if ( nullptr == typeInst ) {
+			return nullptr;
+		}
+		StructInstType * tableInst =
+			followHeadPointerType( typeInst, "virtual_table", errorLocation );
+		if ( nullptr == tableInst ) {
+			return nullptr;
+		}
+		StructInstType * typeIdInst =
+			followHeadPointerType( tableInst, "__cfavir_typeid", errorLocation );
+		delete tableInst;
+		return typeIdInst;
 	}
 
@@ -228,9 +237,16 @@
 		assert( pvt_decl );
 
-		const Type * vtable_type = getVirtualTableType( castExpr );
-		ObjectDecl * table = indexer.lookup( vtable_type );
-		if ( nullptr == table ) {
-			SemanticError( castLocation( castExpr ),
-				"Could not find virtual table instance." );
+		const Type * base_type = getBaseType( castExpr->result );
+		if ( nullptr == base_type ) {
+			castError( castExpr, "Virtual cast target must be a pointer or reference type." );
+		}
+		const Type * type_id_type = getTypeIdType( base_type, castLocation( castExpr ) );
+		if ( nullptr == type_id_type ) {
+			castError( castExpr, "Ill formed virtual cast target type." );
+		}
+		ObjectDecl * type_id = indexer.lookup( type_id_type );
+		delete type_id_type;
+		if ( nullptr == type_id ) {
+			castError( castExpr, "Virtual cast does not target a virtual type." );
 		}
 
@@ -238,5 +254,5 @@
 			new ApplicationExpr( VariableExpr::functionPointer( vcast_decl ), {
 					new CastExpr(
-						new AddressExpr( new VariableExpr( table ) ),
+						new AddressExpr( new VariableExpr( type_id ) ),
 						pointer_to_pvt(1)
 					),
@@ -252,5 +268,4 @@
 		castExpr->set_result( nullptr );
 		delete castExpr;
-		delete vtable_type;
 		return result;
 	}
Index: src/Virtual/Tables.cc
===================================================================
--- src/Virtual/Tables.cc	(revision cd59d28d0ab3255be07ca6dffc9b4f03bd059efd)
+++ src/Virtual/Tables.cc	(revision ecfd7589e4796949fcc35b475a024d4acda6e636)
@@ -10,6 +10,6 @@
 // Created On       : Mon Aug 31 11:11:00 2020
 // Last Modified By : Andrew Beach
-// Last Modified On : Tue Sep  3 14:56:00 2020
-// Update Count     : 0
+// Last Modified On : Thr Apr  8 15:51:00 2021
+// Update Count     : 1
 //
 
@@ -22,6 +22,22 @@
 namespace Virtual {
 
+std::string typeIdType( std::string const & type_name ) {
+	return "__cfatid_struct_" + type_name;
+}
+
+std::string typeIdName( std::string const & type_name ) {
+	return "__cfatid_" + type_name;
+}
+
+static std::string typeIdTypeToInstance( std::string const & type_name ) {
+	return typeIdName(type_name.substr(16));
+}
+
 std::string vtableTypeName( std::string const & name ) {
 	return name + "_vtable";
+}
+
+std::string baseTypeName( std::string const & vtable_type_name ) {
+	return vtable_type_name.substr(0, vtable_type_name.size() - 7);
 }
 
@@ -81,4 +97,8 @@
 				inits.push_back(
 						new SingleInit( new AddressExpr( new NameExpr( parentInstance ) ) ) );
+			} else if ( std::string( "__cfavir_typeid" ) == field->name ) {
+				std::string const & baseType = baseTypeName( vtableType->name );
+				std::string const & typeId = typeIdName( baseType );
+				inits.push_back( new SingleInit( new AddressExpr( new NameExpr( typeId ) ) ) );
 			} else if ( std::string( "size" ) == field->name ) {
 				inits.push_back( new SingleInit( new SizeofExpr( objectType->clone() ) ) );
@@ -147,3 +167,43 @@
 }
 
-}
+ObjectDecl * makeTypeIdForward() {
+	return nullptr;
+}
+
+Attribute * linkonce( const std::string & subsection ) {
+	const std::string section = "\".gnu.linkonce." + subsection + "\"";
+	// Adjust for terminator and quotes.
+	size_t str_size = section.size() + 1 - 2;
+	return new Attribute( "section", {
+		new ConstantExpr( Constant(
+			new ArrayType(
+				noQualifiers,
+				new BasicType( noQualifiers, BasicType::Char ),
+				new ConstantExpr( Constant::from_ulong( str_size ) ),
+				false, false ),
+			section,
+			std::nullopt
+		) ),
+	} );
+}
+
+ObjectDecl * makeTypeIdInstance( StructInstType const * typeIdType ) {
+	assert( typeIdType );
+	StructInstType * type = typeIdType->clone();
+	type->tq.is_const = true;
+	std::string const & typeid_name = typeIdTypeToInstance( typeIdType->name );
+	return new ObjectDecl(
+		typeid_name,
+		noStorageClasses,
+		LinkageSpec::Cforall,
+		/* bitfieldWidth */ nullptr,
+		type,
+		new ListInit( { new SingleInit(
+			new AddressExpr( new NameExpr( "__cfatid_exception_t" ) )
+			) } ),
+		{ linkonce( typeid_name ) },
+		noFuncSpecifiers
+	);
+}
+
+}
Index: src/Virtual/Tables.h
===================================================================
--- src/Virtual/Tables.h	(revision cd59d28d0ab3255be07ca6dffc9b4f03bd059efd)
+++ src/Virtual/Tables.h	(revision ecfd7589e4796949fcc35b475a024d4acda6e636)
@@ -10,6 +10,6 @@
 // Created On       : Mon Aug 31 11:07:00 2020
 // Last Modified By : Andrew Beach
-// Last Modified On : Tue Sep  1 14:29:00 2020
-// Update Count     : 0
+// Last Modified On : Thr Apr  8 15:55:00 2021
+// Update Count     : 1
 //
 
@@ -22,4 +22,6 @@
 namespace Virtual {
 
+std::string typeIdType( std::string const & type_name );
+std::string typeIdName( std::string const & type_name );
 std::string vtableTypeName( std::string const & type_name );
 std::string instanceName( std::string const & vtable_name );
@@ -50,3 +52,8 @@
  */
 
+ObjectDecl * makeTypeIdInstance( StructInstType const * typeIdType );
+/* Build an instance of the type-id from the type of the type-id.
+ * TODO: Should take the parent type. Currently locked to the exception_t.
+ */
+
 }
