Index: src/AST/Expr.hpp
===================================================================
--- src/AST/Expr.hpp	(revision 29075d1e4c22e096eb350d86267c83b273bb0de7)
+++ src/AST/Expr.hpp	(revision ecf38123a0e4f99e0d73b57ef72d89c766288f78)
@@ -330,4 +330,10 @@
 enum GeneratedFlag { ExplicitCast, GeneratedCast };
 
+/// Even within the basic cast expression there are variants:
+/// CCast - C-Style Cast: A backwards compatable cast from C.
+/// CoerceCast - Coercion Cast: Change the type without changing the value.
+/// ReturnCast - Ascription Cast: Requires the given expression result type.
+enum CastKind { CCast, CoerceCast, ReturnCast };
+
 /// A type cast, e.g. `(int)e`
 class CastExpr final : public Expr {
@@ -336,16 +342,10 @@
 	GeneratedFlag isGenerated;
 
-	enum CastKind {
-		Default, // C
-		Coerce, // reinterpret cast
-		Return  // overload selection
-	};
-
-	CastKind kind = Default;
+	CastKind kind = CCast;
 
 	CastExpr( const CodeLocation & loc, const Expr * a, const Type * to,
-		GeneratedFlag g = GeneratedCast, CastKind kind = Default ) : Expr( loc, to ), arg( a ), isGenerated( g ), kind( kind ) {}
+		GeneratedFlag g = GeneratedCast, CastKind kind = CCast ) : Expr( loc, to ), arg( a ), isGenerated( g ), kind( kind ) {}
 	/// Cast-to-void
-	CastExpr( const CodeLocation & loc, const Expr * a, GeneratedFlag g = GeneratedCast, CastKind kind = Default );
+	CastExpr( const CodeLocation & loc, const Expr * a, GeneratedFlag g = GeneratedCast, CastKind kind = CCast );
 
 	/// Wrap a cast expression around an existing expression (always generated)
Index: src/CodeGen/CodeGenerator.cpp
===================================================================
--- src/CodeGen/CodeGenerator.cpp	(revision 29075d1e4c22e096eb350d86267c83b273bb0de7)
+++ src/CodeGen/CodeGenerator.cpp	(revision ecf38123a0e4f99e0d73b57ef72d89c766288f78)
@@ -680,10 +680,27 @@
 	extension( expr );
 	output << "(";
-	if ( expr->result->isVoid() ) {
-		output << "(void)";
-	} else {
-		output << "(";
+	switch ( expr->kind ) {
+	case ast::CCast:
+		if ( expr->result->isVoid() ) {
+			output << "(void)";
+		} else {
+			output << "(";
+			output << genType( expr->result, "", options );
+			output << ")";
+		}
+		break;
+	case ast::CoerceCast:
+		assertf( ast::CoerceCast != expr->kind, "Coercion cast is not implemented." );
+		// And likely shouldn't reach code generation when it is implemented.
+		break;
+	case ast::ReturnCast:
+		// This should be invisible in the resulting C code.
+		// Can we insert a check here?
+		//assert( ResolvExpr::typesCompatable(???) );
+		if ( options.genC ) break;
+		output << "(return ";
 		output << genType( expr->result, "", options );
 		output << ")";
+		break;
 	}
 	expr->arg->accept( *visitor );
Index: src/GenPoly/Lvalue.cpp
===================================================================
--- src/GenPoly/Lvalue.cpp	(revision 29075d1e4c22e096eb350d86267c83b273bb0de7)
+++ src/GenPoly/Lvalue.cpp	(revision ecf38123a0e4f99e0d73b57ef72d89c766288f78)
@@ -315,5 +315,4 @@
 		SemanticWarning( expr->arg->location,
 			Warning::RvalueToReferenceConversion, toCString( expr->arg ) );
-
 
 		// allowing conversion in the rvalue to const ref case
@@ -366,8 +365,7 @@
 			ret = new ast::AddressExpr( ret->location, ret );
 		}
-		if ( expr->arg->get_lvalue() &&
-				!ResolvExpr::typesCompatible(
-					srcType,
-					strict_dynamic_cast<ast::ReferenceType const *>( dstType )->base ) ) {
+		if ( !ResolvExpr::typesCompatible(
+				srcType,
+				strict_dynamic_cast<ast::ReferenceType const *>( dstType )->base ) ) {
 			// Must keep cast if cast-to type is different from the actual type.
 			return ast::mutate_field( expr, &ast::CastExpr::arg, ret );
@@ -384,5 +382,5 @@
 		}
 		// Must keep cast if types are different.
-		if ( !ResolvExpr::typesCompatibleIgnoreQualifiers(
+		if ( !ResolvExpr::typesCompatible(
 				dstType->stripReferences(),
 				srcType->stripReferences() ) ) {
@@ -397,25 +395,18 @@
 	} else {
 		assert( 0 == diff );
-		// Remove useless generated casts.
-		if ( expr->isGenerated == ast::GeneratedFlag::GeneratedCast &&
-				ResolvExpr::typesCompatible(
+		// Must keep cast if types are different. (Or it is explicit.)
+		if ( ast::ExplicitCast == expr->isGenerated ||
+				!ResolvExpr::typesCompatible(
 					expr->result,
 					expr->arg->result ) ) {
-			PRINT(
-				std::cerr << "types are compatible, removing cast: " << expr << '\n';
-				std::cerr << "-- " << expr->result << '\n';
-				std::cerr << "-- " << expr->arg->result << std::endl;
-			)
-			auto argAsEnum = expr->arg.as<ast::EnumInstType>();
-			auto resultAsEnum = expr->result.as<ast::EnumInstType>();
-			if (argAsEnum && resultAsEnum) {
-				if (argAsEnum->base->name != resultAsEnum->base->name) {
-					return expr;
-				}
-			}
-			return ast::mutate_field( expr->arg.get(),
-					&ast::Expr::env, expr->env.get() );
-		}
-		return expr;
+			return expr;
+		}
+		PRINT(
+			std::cerr << "types are compatible, removing cast: " << expr << '\n';
+			std::cerr << "-- " << expr->result << '\n';
+			std::cerr << "-- " << expr->arg->result << std::endl;
+		)
+		return ast::mutate_field( expr->arg.get(),
+				&ast::Expr::env, expr->env.get() );
 	}
 }
Index: src/Parser/ExpressionNode.cpp
===================================================================
--- src/Parser/ExpressionNode.cpp	(revision 29075d1e4c22e096eb350d86267c83b273bb0de7)
+++ src/Parser/ExpressionNode.cpp	(revision ecf38123a0e4f99e0d73b57ef72d89c766288f78)
@@ -652,5 +652,5 @@
 		DeclarationNode * decl_node,
 		ExpressionNode * expr_node,
-		ast::CastExpr::CastKind kind ) {
+		ast::CastKind kind ) {
 	ast::Type * targetType = maybeMoveBuildType( decl_node );
 	if ( dynamic_cast<ast::VoidType *>( targetType ) ) {
Index: src/Parser/ExpressionNode.hpp
===================================================================
--- src/Parser/ExpressionNode.hpp	(revision 29075d1e4c22e096eb350d86267c83b273bb0de7)
+++ src/Parser/ExpressionNode.hpp	(revision ecf38123a0e4f99e0d73b57ef72d89c766288f78)
@@ -69,5 +69,5 @@
 ast::DimensionExpr * build_dimensionref( const CodeLocation &, const std::string * name );
 
-ast::Expr * build_cast( const CodeLocation &, DeclarationNode * decl_node, ExpressionNode * expr_node, ast::CastExpr::CastKind kind = ast::CastExpr::Default );
+ast::Expr * build_cast( const CodeLocation &, DeclarationNode * decl_node, ExpressionNode * expr_node, ast::CastKind kind = ast::CCast );
 ast::Expr * build_keyword_cast( const CodeLocation &, ast::AggregateDecl::Aggregate target, ExpressionNode * expr_node );
 ast::Expr * build_virtual_cast( const CodeLocation &, DeclarationNode * decl_node, ExpressionNode * expr_node );
Index: src/Parser/parser.yy
===================================================================
--- src/Parser/parser.yy	(revision 29075d1e4c22e096eb350d86267c83b273bb0de7)
+++ src/Parser/parser.yy	(revision ecf38123a0e4f99e0d73b57ef72d89c766288f78)
@@ -979,5 +979,5 @@
 		{ $$ = new ExpressionNode( new ast::VirtualCastExpr( yylloc, maybeMoveBuild( $5 ), maybeMoveBuildType( $3 ) ) ); }
 	| '(' RETURN type_no_function ')' cast_expression	// CFA
-		{ $$ = new ExpressionNode( build_cast( yylloc, $3, $5, ast::CastExpr::Return ) ); }
+		{ $$ = new ExpressionNode( build_cast( yylloc, $3, $5, ast::ReturnCast ) ); }
 	| '(' COERCE type_no_function ')' cast_expression	// CFA
 		{ SemanticError( yylloc, "Coerce cast is currently unimplemented." ); $$ = nullptr; }
Index: src/ResolvExpr/CandidateFinder.cpp
===================================================================
--- src/ResolvExpr/CandidateFinder.cpp	(revision 29075d1e4c22e096eb350d86267c83b273bb0de7)
+++ src/ResolvExpr/CandidateFinder.cpp	(revision ecf38123a0e4f99e0d73b57ef72d89c766288f78)
@@ -1220,5 +1220,5 @@
 			finder.allowVoid = true;
 		}
-		if ( castExpr->kind == ast::CastExpr::Return ) {
+		if ( ast::ReturnCast == castExpr->kind ) {
 			finder.strictMode = true;
 			finder.find( castExpr->arg, ResolveMode::withAdjustment() );
