Index: src/ResolvExpr/CandidateFinder.cpp
===================================================================
--- src/ResolvExpr/CandidateFinder.cpp	(revision 0f5e8cdba2bacf645f79f523a3a2c2aa393e7d17)
+++ src/ResolvExpr/CandidateFinder.cpp	(revision f678c53bb53e8e34a5a75ce6def17271274e1f80)
@@ -513,8 +513,25 @@
 					// add new result
 					assert( common );
-						results.emplace_back(
-							i, expr, std::move( env ), std::move( need ), std::move( have ), std::move( open ),
-							nextArg + 1, nTuples, expl.cost, expl.exprs.size() == 1 ? 0 : 1, j );
-					//}
+
+					auto paramAsEnum = dynamic_cast<const ast::EnumInstType *>(paramType);
+					auto argAsEnum =dynamic_cast<const ast::EnumInstType *>(argType);
+					if (paramAsEnum && argAsEnum) {
+						if (paramAsEnum->base->name != argAsEnum->base->name) {
+							Cost c = castCost(argType, paramType, expr, context.symtab, env);
+							if (c < Cost::infinity) {
+								CandidateFinder subFinder( context, env );
+								expr = subFinder.makeEnumOffsetCast(argAsEnum, paramAsEnum, expr, c);
+								results.emplace_back(
+									i, expr, std::move( env ), std::move( need ), std::move( have ), std::move( open ),
+									nextArg + 1, nTuples, expl.cost + c, expl.exprs.size() == 1 ? 0 : 1, j );
+								continue;
+							} else {
+								std::cerr << "Cannot instantiate " << paramAsEnum->base->name <<  " with " << argAsEnum->base->name << std::endl;
+							}
+						}
+					}
+					results.emplace_back(
+						i, expr, std::move( env ), std::move( need ), std::move( have ), std::move( open ),
+						nextArg + 1, nTuples, expl.cost, expl.exprs.size() == 1 ? 0 : 1, j );
 				}
 			}
@@ -632,4 +649,8 @@
 			const ast::BaseInstType * aggrInst, const ast::Expr * expr,
 			const Candidate & cand, const Cost & addedCost, const std::string & name
+		);
+
+		void addEnumValueAsCandidate(const ast::EnumInstType * instType, const ast::Expr * expr,
+			const Cost & addedCost
 		);
 
@@ -676,4 +697,8 @@
 		void postvisit( const ast::QualifiedNameExpr * qualifiedExpr );
 
+		const ast::Expr * makeEnumOffsetCast( const ast::EnumInstType * src, 
+			const ast::EnumInstType * dst
+			, const ast::Expr * expr, Cost minCost );
+
 		void postvisit( const ast::InitExpr * ) {
 			assertf( false, "CandidateFinder should never see a resolved InitExpr." );
@@ -876,4 +901,25 @@
 	}
 
+	void Finder::addEnumValueAsCandidate( const ast::EnumInstType * enumInst, const ast::Expr * expr,
+		const Cost & addedCost
+	) {
+		if ( enumInst->base->base ) {
+			CandidateFinder finder( context, tenv );
+			auto location = expr->location;
+			auto callExpr = new ast::UntypedExpr(
+				location, new ast::NameExpr( location, "valueE" ), {expr}
+			);
+			finder.find( callExpr );
+			CandidateList winners = findMinCost( finder.candidates );
+			if (winners.size() != 1) {
+				SemanticError( callExpr, "Ambiguous expression in valueE..." );
+			}
+			CandidateRef & choice = winners.front();
+			choice->cost += addedCost;
+			addAnonConversions(choice);
+			candidates.emplace_back( std::move(choice) );
+		}
+	}
+
 	/// Adds implicit struct-conversions to the alternative list
 	void Finder::addAnonConversions( const CandidateRef & cand ) {
@@ -894,22 +940,8 @@
 			addAggMembers( unionInst, aggrExpr, *cand, Cost::unsafe, "" );
 		} else if ( auto enumInst = aggrExpr->result.as< ast::EnumInstType >() ) {
-			if ( enumInst->base->base ) {
-				CandidateFinder finder( context, tenv );
-				auto location = aggrExpr->location;
-				auto callExpr = new ast::UntypedExpr(
-					location, new ast::NameExpr( location, "valueE" ), {aggrExpr}
-				);
-				finder.find( callExpr );
-				CandidateList winners = findMinCost( finder.candidates );
-				if (winners.size() != 1) {
-					SemanticError( callExpr, "Ambiguous expression in valueE..." );
-				}
-				CandidateRef & choice = winners.front();
-				choice->cost = Cost::unsafe;
-				candidates.emplace_back( std::move(choice) );
-			}
-
-		}
-	}
+			addEnumValueAsCandidate(enumInst, aggrExpr, Cost::unsafe);
+		}
+	}
+	
 
 	/// Adds aggregate member interpretations
@@ -1180,4 +1212,47 @@
 	}
 
+	// src is a subset of dst
+	const ast::Expr * Finder::makeEnumOffsetCast( const ast::EnumInstType * src, 
+		const ast::EnumInstType * dst,
+		const ast::Expr * expr,
+		Cost minCost ) {
+		
+		auto srcDecl = src->base;
+		auto dstDecl = dst->base;
+
+		if (srcDecl->name == dstDecl->name) return expr;
+
+		for (auto& dstChild: dstDecl->inlinedDecl) {
+			Cost c = castCost(src, dstChild, false, symtab, tenv);
+			ast::CastExpr * castToDst;
+			if (c<minCost) {
+				unsigned offset = dstDecl->calChildOffset(dstChild.get());
+				if (offset > 0) {
+					auto untyped = ast::UntypedExpr::createCall(
+						expr->location, 
+						"?+?", 
+						{ new ast::CastExpr( expr, new ast::BasicType(ast::BasicKind::SignedInt) ),
+						ast::ConstantExpr::from_int(expr->location, offset)});
+					CandidateFinder finder(context, tenv);
+					finder.find( untyped );
+					CandidateList winners = findMinCost( finder.candidates );
+					CandidateRef & choice = winners.front();
+					// choice->expr = referenceToRvalueConversion( choice->expr, choice->cost );
+					choice->expr = new ast::CastExpr(expr->location, choice->expr, dstChild, ast::GeneratedFlag::ExplicitCast);
+					// castToDst = new ast::CastExpr(choice->expr, dstChild);
+					castToDst = new ast::CastExpr( 
+						makeEnumOffsetCast( src, dstChild, choice->expr, minCost ),
+					 dst);
+
+				} else {
+					castToDst = new ast::CastExpr( expr, dst );
+				}
+				return castToDst;
+			}
+		}
+		SemanticError(expr, src->base->name + " is not a subtype of " + dst->base->name);
+		return nullptr;
+	}
+
 	void Finder::postvisit( const ast::CastExpr * castExpr ) {
 		ast::ptr< ast::Type > toType = castExpr->result;
@@ -1229,4 +1304,12 @@
 					? conversionCost( cand->expr->result, toType, cand->expr->get_lvalue(), symtab, cand->env )
 					: castCost( cand->expr->result, toType, cand->expr->get_lvalue(), symtab, cand->env );
+			
+			// Redefine enum cast
+			auto argAsEnum = cand->expr->result.as<ast::EnumInstType>();
+			auto toAsEnum = toType.as<ast::EnumInstType>();
+			if ( argAsEnum && toAsEnum && argAsEnum->name != toAsEnum->name ) {	
+				ast::ptr<ast::Expr> offsetExpr = makeEnumOffsetCast(argAsEnum, toAsEnum, cand->expr, thisCost);
+				cand->expr = offsetExpr;
+			}
 
 			PRINT(
@@ -1246,8 +1329,6 @@
 					minCastCost = thisCost;
 					matches.clear();
-
-
-				}
-				// ambiguous case, still output candidates to print in error message
+				}
+				// ambigious case, still output candidates to print in error message
 				if ( cand->cost == minExprCost && thisCost == minCastCost ) {
 					CandidateRef newCand = std::make_shared<Candidate>(
@@ -1264,5 +1345,4 @@
 		}
 		candidates = std::move(matches);
-
 		//CandidateList minArgCost = findMinCost( matches );
 		//promoteCvtCost( minArgCost );
@@ -1374,5 +1454,5 @@
 			}
 		} else {
-			declList = symtab.lookupId( nameExpr->name );
+			declList = symtab.lookupIdIgnoreHidden( nameExpr->name );
 		}
 		PRINT( std::cerr << "nameExpr is " << nameExpr->name << std::endl; )
@@ -1386,14 +1466,4 @@
 			ast::Expr * newExpr = data.combine( nameExpr->location, cost );
 
-			// bool bentConversion = false;
-			// if ( auto inst = newExpr->result.as<ast::EnumInstType>() ) {
-			// 	if ( inst->base && inst->base->base ) {
-			// 		bentConversion = true;
-			// 	}
-			// }
-
-			// CandidateRef newCand = std::make_shared<Candidate>(
-			// 	newExpr, copy( tenv ), ast::OpenVarSet{}, ast::AssertionSet{}, bentConversion? Cost::safe: Cost::zero,
-			// 	cost );
 			CandidateRef newCand = std::make_shared<Candidate>(
 				newExpr, copy( tenv ), ast::OpenVarSet{}, ast::AssertionSet{}, Cost::zero,
@@ -1813,12 +1883,8 @@
 			if ( const ast::EnumInstType * enumInstType =
 				dynamic_cast<const ast::EnumInstType *>( t ) ) {
-				if ( enumInstType->base->name == expr->type_decl->name ) {
+				if ( (enumInstType->base->name == expr->type_name)
+					|| (expr->type_decl && enumInstType->base->name == expr->type_decl->name) ) {
 					Cost cost = Cost::zero;
 					ast::Expr * newExpr = data.combine( expr->location, cost );
-					// CandidateRef newCand =
-					// 	std::make_shared<Candidate>(
-					// 		newExpr, copy( tenv ), ast::OpenVarSet{},
-					// 		ast::AssertionSet{}, Cost::safe, cost
-					// 	);
 					CandidateRef newCand =
 						std::make_shared<Candidate>(
@@ -2096,4 +2162,43 @@
 
 	return expr;
+}
+
+const ast::Expr * CandidateFinder::makeEnumOffsetCast( const ast::EnumInstType * src, 
+	const ast::EnumInstType * dst,
+	const ast::Expr * expr,
+	Cost minCost ) {
+	
+	auto srcDecl = src->base;
+	auto dstDecl = dst->base;
+
+	if (srcDecl->name == dstDecl->name) return expr;
+
+	for (auto& dstChild: dstDecl->inlinedDecl) {
+		Cost c = castCost(src, dstChild, false, context.symtab, env);
+		ast::CastExpr * castToDst;
+		if (c<minCost) {
+			unsigned offset = dstDecl->calChildOffset(dstChild.get());
+			if (offset > 0) {
+				auto untyped = ast::UntypedExpr::createCall(
+					expr->location, 
+					"?+?", 
+					{ new ast::CastExpr( expr, new ast::BasicType(ast::BasicKind::SignedInt) ),
+					ast::ConstantExpr::from_int(expr->location, offset)});
+				CandidateFinder finder(context, env);
+				finder.find( untyped );
+				CandidateList winners = findMinCost( finder.candidates );
+				CandidateRef & choice = winners.front();
+				choice->expr = new ast::CastExpr(expr->location, choice->expr, dstChild, ast::GeneratedFlag::ExplicitCast);
+				castToDst = new ast::CastExpr( 
+					makeEnumOffsetCast( src, dstChild, choice->expr, minCost ),
+					dst);
+			} else {
+				castToDst = new ast::CastExpr( expr, dst );
+			}
+			return castToDst;
+		}
+	}
+	SemanticError(expr, src->base->name + " is not a subtype of " + dst->base->name);
+	return nullptr;
 }
 
Index: src/ResolvExpr/CandidateFinder.hpp
===================================================================
--- src/ResolvExpr/CandidateFinder.hpp	(revision 0f5e8cdba2bacf645f79f523a3a2c2aa393e7d17)
+++ src/ResolvExpr/CandidateFinder.hpp	(revision f678c53bb53e8e34a5a75ce6def17271274e1f80)
@@ -58,4 +58,7 @@
 	iterator end() { return candidates.end(); }
 	const_iterator end() const { return candidates.end(); }
+
+	const ast::Expr * makeEnumOffsetCast( const ast::EnumInstType * src, 
+		const ast::EnumInstType * dst, const ast::Expr * expr, Cost minCost );
 };
 
Index: src/ResolvExpr/CastCost.cpp
===================================================================
--- src/ResolvExpr/CastCost.cpp	(revision 0f5e8cdba2bacf645f79f523a3a2c2aa393e7d17)
+++ src/ResolvExpr/CastCost.cpp	(revision f678c53bb53e8e34a5a75ce6def17271274e1f80)
@@ -36,4 +36,9 @@
 namespace ResolvExpr {
 
+Cost castCost(
+	const ast::Type * src, const ast::Type * dst, bool srcIsLvalue,
+	const ast::SymbolTable & symtab, const ast::TypeEnvironment & env
+);
+
 namespace {
 	struct CastCost : public ConversionCost {
@@ -45,4 +50,8 @@
 			const ast::TypeEnvironment & env, CostCalculation costFunc )
 		: ConversionCost( dst, srcIsLvalue, symtab, env, costFunc ) {}
+
+		void postvisit( const ast::EnumInstType * enumInst ) {
+			cost = conversionCost( enumInst, dst, srcIsLvalue, symtab, env );
+		}
 
 		void postvisit( const ast::BasicType * basicType ) {
@@ -104,10 +113,4 @@
 					cost = Cost::unsafe;
 				}
-			}
-		}
-
-		void postvist( const ast::EnumInstType * ) {
-			if ( auto basic = dynamic_cast< const ast::BasicType * >(dst) ) {
-				if ( basic->isInteger() ) cost = Cost::unsafe;
 			}
 		}
Index: src/ResolvExpr/CommonType.cpp
===================================================================
--- src/ResolvExpr/CommonType.cpp	(revision 0f5e8cdba2bacf645f79f523a3a2c2aa393e7d17)
+++ src/ResolvExpr/CommonType.cpp	(revision f678c53bb53e8e34a5a75ce6def17271274e1f80)
@@ -636,6 +636,11 @@
 	void postvisit( const ast::UnionInstType * ) {}
 
-	void postvisit( const ast::EnumInstType * enumInst ) {
-		if ( enumInst->base && !enumInst->base->isTyped ) {
+	void postvisit( const ast::EnumInstType * param ) {
+		auto argAsEnumInst = dynamic_cast<const ast::EnumInstType *>(type2);
+		if ( argAsEnumInst ) {
+			const ast::EnumDecl* paramDecl = param->base;
+			const ast::EnumDecl* argDecl = argAsEnumInst->base;
+			if (argDecl->isSubTypeOf(paramDecl)) result = param;
+		} else if ( param->base && !param->base->isTyped ) {
 			auto basicType = new ast::BasicType( ast::BasicKind::UnsignedInt );
 			result = commonType( basicType, type2, tenv, need, have, open, widen);
Index: src/ResolvExpr/ConversionCost.cpp
===================================================================
--- src/ResolvExpr/ConversionCost.cpp	(revision 0f5e8cdba2bacf645f79f523a3a2c2aa393e7d17)
+++ src/ResolvExpr/ConversionCost.cpp	(revision f678c53bb53e8e34a5a75ce6def17271274e1f80)
@@ -191,4 +191,9 @@
 }
 
+Cost enumCastCost (
+	const ast::EnumInstType * src, const ast::EnumInstType * dst, 
+	const ast::SymbolTable & symtab, const ast::TypeEnvironment & env
+);
+
 static Cost convertToReferenceCost( const ast::Type * src, const ast::Type * dst, bool srcIsLvalue,
 		int diff, const ast::SymbolTable & symtab, const ast::TypeEnvironment & env,
@@ -359,11 +364,6 @@
 
 void ConversionCost::postvisit( const ast::EnumInstType * inst ) {
-	if ( auto dstAsInst = dynamic_cast<const ast::EnumInstType *>( dst ) ) {
-		if (inst->base && dstAsInst->base) {
-			if (inst->base->name == dstAsInst->base->name) {
-				cost = Cost::zero;
-				return;
-			}
-		}
+	if ( auto dstInst = dynamic_cast<const ast::EnumInstType *>( dst ) ) {
+		cost = enumCastCost(inst, dstInst, symtab, env);
 		return;
 	}
@@ -481,4 +481,21 @@
 }
 
+// (dst) src is safe is src is a subtype of dst, or dst {inline src, ...}
+Cost enumCastCost (
+	const ast::EnumInstType * src, const ast::EnumInstType * dst, 
+	const ast::SymbolTable & symtab, const ast::TypeEnvironment & env
+) {
+	auto srcDecl = src->base;
+	auto dstDecl = dst->base;
+	if (srcDecl->name == dstDecl->name) return Cost::safe;
+	Cost minCost = Cost::infinity;
+	for (auto child: dstDecl->inlinedDecl) {
+		Cost c = enumCastCost(src, child, symtab, env) + Cost::safe;
+		if (c<minCost) minCost = c;
+	}
+	return minCost;
+}
+
+
 // size_t ConversionCost::traceId = Stats::Heap::new_stacktrace_id("ConversionCost");
 
Index: src/ResolvExpr/Resolver.cpp
===================================================================
--- src/ResolvExpr/Resolver.cpp	(revision 0f5e8cdba2bacf645f79f523a3a2c2aa393e7d17)
+++ src/ResolvExpr/Resolver.cpp	(revision f678c53bb53e8e34a5a75ce6def17271274e1f80)
@@ -201,4 +201,12 @@
 				&& typesCompatible( castExpr->arg->result, castExpr->result )
 			) {
+				auto argAsEnum = castExpr->arg.as<ast::EnumInstType>();
+				auto resultAsEnum = castExpr->result.as<ast::EnumInstType>();
+				if (argAsEnum && resultAsEnum) {
+					if (argAsEnum->base->name != resultAsEnum->base->name) {
+						std::cerr << "Enum Cast: " << argAsEnum->base->name << " to " << resultAsEnum->base->name << std::endl;
+						return castExpr;
+					}
+				}
 				// generated cast is the same type as its argument, remove it after keeping env
 				return ast::mutate_field(
