Index: src/ResolvExpr/CandidateFinder.cpp
===================================================================
--- src/ResolvExpr/CandidateFinder.cpp	(revision 06601401c36e6b2cf39fa38d23552cf5418850f3)
+++ src/ResolvExpr/CandidateFinder.cpp	(revision af746ccdf606483f8f89907b52e8b9471c72df7c)
@@ -285,5 +285,5 @@
 		const CodeLocation & location,
 		const ast::Type * paramType, const ast::Init * init, const ExplodedArgs & args,
-		std::vector< ArgPack > & results, std::size_t & genStart, const ast::SymbolTable & symtab,
+		std::vector< ArgPack > & results, std::size_t & genStart, const ResolveContext & context,
 		unsigned nTuples = 0
 	) {
@@ -295,5 +295,5 @@
 				// ^^^ need to handle the case where a tuple has a default argument
 				if ( ! instantiateArgument( location,
-					type, nullptr, args, results, genStart, symtab, nTuples ) ) return false;
+					type, nullptr, args, results, genStart, context, nTuples ) ) return false;
 				nTuples = 0;
 			}
@@ -510,9 +510,30 @@
 
 				// attempt to unify types
-				if ( unify( paramType, argType, env, need, have, open ) ) {
+				ast::ptr<ast::Type> common;
+				if ( unify( paramType, argType, env, need, have, open, common ) ) {
 					// add new result
-					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 );
+					assert( common );
+					// auto attrType = common.as<ast::EnumAttrType>();
+					// if ( attrType && ( attrType->attr == ast::EnumAttribute::Value ) ) {
+					// 	auto callExpr = new ast::UntypedExpr(
+					// 		expr->location, new ast::NameExpr( expr->location, "valueE"), {expr} );
+					// 	CandidateFinder finder( context, env );
+					// 	finder.find( callExpr );
+					// 	CandidateList winners = findMinCost( finder.candidates );
+					// 	if (winners.size() != 1) {
+					// 		SemanticError( callExpr, "Ambiguous expression in valueE" );
+					// 	}
+					// 	CandidateRef & choice = winners.front();
+					// 	choice->expr = referenceToRvalueConversion( choice->expr, choice->cost );
+
+					// 	results.emplace_back(
+					// 		i, choice->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 );
+					// } else {
+						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 );
+					//}
 				}
 			}
@@ -786,5 +807,5 @@
 					auto obj = funcDecl->params[i].strict_as<ast::ObjectDecl>();
 					if ( !instantiateArgument( location,
-						funcType->params[i], obj->init, args, results, genStart, symtab)) return;
+						funcType->params[i], obj->init, args, results, genStart, context)) return;
 				}
 				goto endMatch;
@@ -796,5 +817,5 @@
 			// no default args for indirect calls
 			if ( !instantiateArgument( location,
-				param, nullptr, args, results, genStart, symtab ) ) return;
+				param, nullptr, args, results, genStart, context ) ) return;
 		}
 
@@ -891,62 +912,21 @@
 		} else if ( auto unionInst = aggrExpr->result.as< ast::UnionInstType >() ) {
 			addAggMembers( unionInst, aggrExpr, *cand, Cost::unsafe, "" );
-		} 
-		else if ( auto enumInst = aggrExpr->result.as< ast::EnumInstType >() ) {
-			if (enumInst->base && enumInst->base->base) {
-            const CodeLocation &location = cand->expr->location;
-
-            CandidateFinder funcFinder(context, tenv);
-            auto nameExpr = new ast::NameExpr(location, "valueE");
-            ResolveMode mode = {true, false, selfFinder.candidates.empty()};
-            funcFinder.find( nameExpr, mode );
-
-            // make variableExpr itself the candidate for the value Call
-            ExplodedArgs argExpansions;
-            argExpansions.emplace_back();
-            auto &argE = argExpansions.back();
-
-            argE.emplace_back(*cand, symtab); // Use the typed name expr as param for value
-
-            CandidateList found;
-            SemanticErrorException errors;
-
-            for (CandidateRef &func : funcFinder) {
-                try {
-                    const ast::Type *funcResult =
-                        func->expr->result->stripReferences();
-                    if (auto pointer = dynamic_cast<const ast::PointerType *>(
-                            funcResult)) {
-                        if (auto function =
-                                pointer->base.as<ast::FunctionType>()) {
-                            CandidateRef newFunc{new Candidate{*func}};
-                            newFunc->expr = referenceToRvalueConversion(
-                                newFunc->expr, newFunc->cost);
-                            makeFunctionCandidates( location,
-                                                   newFunc, function,
-                                                   argExpansions, found );
-                        }
-                    }
-                } catch (SemanticErrorException &e) {
-                    std::cerr
-                        << "Resolving value function should cause an error"
-                        << std::endl;
-                    errors.append(e);
-                }
-            }
-
-            if (found.empty()) {
-                std::cerr << "Resolve value function should always success"
-                          << std::endl;
-            }
-
-            for (CandidateRef &withFunc : found) {
-                withFunc->cost.incSafe();
-                Cost cvtCost =
-                    computeApplicationConversionCost(withFunc, symtab);
-                assert(cvtCost != Cost::infinity);
-
-                candidates.emplace_back(std::move(withFunc));
-            }
-        }
+		} 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.incSafe();
+				candidates.emplace_back( std::move(choice) );
+			}
+
 		}
 	}
@@ -1415,6 +1395,13 @@
 			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{}, Cost::zero,
+				newExpr, copy( tenv ), ast::OpenVarSet{}, ast::AssertionSet{}, bentConversion? Cost::safe: Cost::zero,
 				cost );
 
@@ -1449,64 +1436,4 @@
         auto cand = new Candidate(variableExpr, tenv);
         candidates.emplace_back(cand);
-
-        if (auto enumInst = dynamic_cast<const ast::EnumInstType *>(
-                variableExpr->var->get_type())) {
-            if (enumInst->base && enumInst->base->base) {
-                const CodeLocation &location = cand->expr->location;
-
-                CandidateFinder funcFinder(context, tenv);
-                auto nameExpr = new ast::NameExpr(location, "valueE");
-                ResolveMode mode = {true, false, selfFinder.candidates.empty()};
-                funcFinder.find( nameExpr, mode );
-
-                // make variableExpr itself the candidate for the value Call
-                ExplodedArgs argExpansions;
-                argExpansions.emplace_back();
-                auto &argE = argExpansions.back();
-
-                argE.emplace_back(*cand, symtab);
-
-                CandidateList found;
-                SemanticErrorException errors;
-
-                for (CandidateRef &func : funcFinder) {
-                    try {
-                    const ast::Type *funcResult =
-                        func->expr->result->stripReferences();
-                    if (auto pointer = dynamic_cast<const ast::PointerType *>(
-                            funcResult)) {
-                        if (auto function =
-                                pointer->base.as<ast::FunctionType>()) {
-                            CandidateRef newFunc{new Candidate{*func}};
-                            newFunc->expr = referenceToRvalueConversion(
-                                newFunc->expr, newFunc->cost);
-                            makeFunctionCandidates(variableExpr->location,
-                                                   newFunc, function,
-                                                   argExpansions, found);
-                        }
-                    }
-                    } catch (SemanticErrorException &e) {
-                        std::cerr
-                            << "Resolving value function should cause an error"
-                            << std::endl;
-                        errors.append(e);
-                    }
-                }
-
-                if (found.empty()) {
-                    std::cerr << "Resolve value function should always success"
-                            << std::endl;
-                }
-
-                for (CandidateRef &withFunc : found) {
-                    withFunc->cost.incSafe();
-                    Cost cvtCost =
-                        computeApplicationConversionCost(withFunc, symtab);
-                    assert(cvtCost != Cost::infinity);
-
-                    candidates.emplace_back(std::move(withFunc));
-                }
-            }
-        }
     }
 
@@ -1840,5 +1767,6 @@
 
 				// unification run for side-effects
-				bool canUnify = unify( toType, cand->expr->result, env, need, have, open );
+				ast::ptr<ast::Type> common;
+				bool canUnify = unify( toType, cand->expr->result, env, need, have, open, common );
 				(void) canUnify;
 				Cost thisCost = computeConversionCost( cand->expr->result, toType, cand->expr->get_lvalue(),
@@ -1865,16 +1793,39 @@
 					// ambiguous case, still output candidates to print in error message
 					if ( cand->cost == minExprCost && thisCost == minCastCost ) {
-						CandidateRef newCand = std::make_shared<Candidate>(
-							new ast::InitExpr{
-								initExpr->location,
-								restructureCast( cand->expr, toType ),
-								initAlt.designation },
-							std::move(env), std::move( open ), std::move( need ), cand->cost + thisCost );
-						// currently assertions are always resolved immediately so this should have no effect.
-						// if this somehow changes in the future (e.g. delayed by indeterminate return type)
-						// we may need to revisit the logic.
-						inferParameters( newCand, matches );
-					}
-				}
+						auto commonAsEnumAttr = common.as<ast::EnumAttrType>();
+						if ( commonAsEnumAttr && commonAsEnumAttr->attr == ast::EnumAttribute::Value ) {
+							
+							auto callExpr = new ast::UntypedExpr(
+								cand->expr->location, new ast::NameExpr( cand->expr->location, "valueE"), {cand->expr} );
+							CandidateFinder finder( context, env );
+							finder.find( callExpr );
+							CandidateList winners = findMinCost( finder.candidates );
+							if (winners.size() != 1) {
+								SemanticError( callExpr, "Ambiguous expression in valueE" );
+							}
+							CandidateRef & choice = winners.front();
+							// assert( valueCall->result );
+							CandidateRef newCand = std::make_shared<Candidate>(
+								new ast::InitExpr{
+									initExpr->location,
+									// restructureCast( cand->expr, toType ),
+									choice->expr,
+									initAlt.designation },
+								std::move(env), std::move( open ), std::move( need ), cand->cost + thisCost );
+								inferParameters( newCand, matches );
+						} else {
+							CandidateRef newCand = std::make_shared<Candidate>(
+								new ast::InitExpr{
+									initExpr->location,
+									restructureCast( cand->expr, toType ),
+									initAlt.designation },
+								std::move(env), std::move( open ), std::move( need ), cand->cost + thisCost );
+							// currently assertions are always resolved immediately so this should have no effect.
+							// if this somehow changes in the future (e.g. delayed by indeterminate return type)
+							// we may need to revisit the logic.
+							inferParameters( newCand, matches );	
+						}
+					}			
+				}	
 			}
 		}
@@ -1901,5 +1852,5 @@
 						std::make_shared<Candidate>(
 							newExpr, copy( tenv ), ast::OpenVarSet{},
-							ast::AssertionSet{}, Cost::zero, cost
+							ast::AssertionSet{}, Cost::safe, cost
 						);
 
@@ -2201,4 +2152,21 @@
 }
 
+// get the valueE(...) ApplicationExpr that returns the enum value
+const ast::Expr * getValueEnumCall( 
+	const ast::Expr * expr, 
+	const ResolvExpr::ResolveContext & context, const ast::TypeEnvironment & env ) {
+		auto callExpr = new ast::UntypedExpr(
+			expr->location, new ast::NameExpr( expr->location, "valueE"), {expr} );
+		CandidateFinder finder( context, env );
+		finder.find( callExpr );
+		CandidateList winners = findMinCost( finder.candidates );
+		if (winners.size() != 1) {
+			SemanticError( callExpr, "Ambiguous expression in valueE" );
+		}
+		CandidateRef & choice = winners.front();
+		return choice->expr;
+		// return std::move( choice->expr.get() );
+}
+
 } // namespace ResolvExpr
 
Index: src/ResolvExpr/CandidateFinder.hpp
===================================================================
--- src/ResolvExpr/CandidateFinder.hpp	(revision 06601401c36e6b2cf39fa38d23552cf5418850f3)
+++ src/ResolvExpr/CandidateFinder.hpp	(revision af746ccdf606483f8f89907b52e8b9471c72df7c)
@@ -70,4 +70,7 @@
 	const ast::Expr * expr, Cost & cost );
 
+const ast::Expr * getValueEnumCall(const ast::Expr * expr,
+	const ResolvExpr::ResolveContext & context, const ast::TypeEnvironment & env );
+
 } // namespace ResolvExpr
 
Index: src/ResolvExpr/CommonType.cc
===================================================================
--- src/ResolvExpr/CommonType.cc	(revision 06601401c36e6b2cf39fa38d23552cf5418850f3)
+++ src/ResolvExpr/CommonType.cc	(revision af746ccdf606483f8f89907b52e8b9471c72df7c)
@@ -385,7 +385,5 @@
 		} else if ( const ast::EnumInstType * enumInst = dynamic_cast< const ast::EnumInstType * >( type2 ) ) {
 			const ast::EnumDecl* enumDecl = enumInst->base;
-			if ( enumDecl->base ) {
-				result = enumDecl->base.get();
-			} else {
+			if ( !enumDecl->base ) {
 				ast::BasicType::Kind kind = commonTypes[ basic->kind ][ ast::BasicType::SignedInt ];
 				if (
@@ -398,14 +396,16 @@
 				}
 			}
-		} else if ( dynamic_cast< const ast::EnumPosType * >( type2 ) ) {
-			ast::BasicType::Kind kind = commonTypes[ basic->kind ][ ast::BasicType::SignedInt ];
-			if (
-				( ( kind == basic->kind && basic->qualifiers >= type2->qualifiers )
-					|| widen.first )
-				&& ( ( kind != basic->kind && basic->qualifiers <= type2->qualifiers )
-					|| widen.second )
-			) {
-				result = new ast::BasicType{ kind, basic->qualifiers | type2->qualifiers };
-			}
+		} else if ( auto type2AsAttr = dynamic_cast< const ast::EnumAttrType * >( type2 ) ) {
+            if ( type2AsAttr->attr == ast::EnumAttribute::Posn ) {
+			    ast::BasicType::Kind kind = commonTypes[ basic->kind ][ ast::BasicType::SignedInt ];
+			    if (
+				    ( ( kind == basic->kind && basic->qualifiers >= type2->qualifiers )
+					    || widen.first )
+				    && ( ( kind != basic->kind && basic->qualifiers <= type2->qualifiers )
+					    || widen.second )
+			    ) {
+				    result = new ast::BasicType{ kind, basic->qualifiers | type2->qualifiers };
+			    }
+            }
 		}
 	}
@@ -426,17 +426,4 @@
 		result = voidPtr;
 		add_qualifiers( result, oPtr->qualifiers );
-	}
-
-	// For a typed enum, we want to unify type1 with the base type of the enum
-	bool tryResolveWithTypedEnum( const ast::Type * type1 ) {
-		if (auto enumInst = dynamic_cast<const ast::EnumInstType *> (type2) ) {
-			ast::OpenVarSet newOpen{ open };
-			if (enumInst->base->base
-				&& unifyExact(type1, enumInst->base->base, tenv, need, have, newOpen, widen)) {
-					result = type1;
-				return true;
-			}
-		}
-		return false;
 	}
 
@@ -607,13 +594,8 @@
 			result = pointer;
 			add_qualifiers( result, type2->qualifiers );
-		} else {
-			tryResolveWithTypedEnum( pointer );
-		}
-	}
-
-	void postvisit( const ast::ArrayType * arr ) {
-		// xxx - does it make sense?
-		tryResolveWithTypedEnum( arr );
-	}
+		}
+	}
+
+	void postvisit( const ast::ArrayType * arr ) {}
 
 	void postvisit( const ast::ReferenceType * ref ) {
@@ -659,36 +641,18 @@
 	}
 
-	void postvisit( const ast::FunctionType * func) {
-		tryResolveWithTypedEnum( func );
-	}
-
-	void postvisit( const ast::StructInstType * inst ) {
-		tryResolveWithTypedEnum( inst );
-	}
-
-	void postvisit( const ast::UnionInstType * inst ) {
-		tryResolveWithTypedEnum( inst );
-	}
+	void postvisit( const ast::FunctionType * func) {}
+
+	void postvisit( const ast::StructInstType * inst ) {}
+
+	void postvisit( const ast::UnionInstType * inst ) {}
 
 	void postvisit( const ast::EnumInstType * enumInst ) {
-		// if ( dynamic_cast<const ast::EnumPosType *>(enumInst) ) {
-		// 	result = enumInst;
-		// } else 
-		if (!dynamic_cast<const ast::EnumInstType *>(type2)) {
-			result = commonType( type2, enumInst, tenv, need, have, open, widen);
-		}
-	}
-
-	void postvisit( const ast::EnumPosType * enumPos ) {
-		if ( auto type2AsPos = dynamic_cast<const ast::EnumPosType *>(type2) ) {
-			// result = commonType( type2AsPos->instance, enumPos->instance, tenv, need, have, open, widen );
-			// result = enumPos;
-			if ( enumPos->instance->base->name == type2AsPos->instance->base->name ) {
-				result = type2;
-			}
-		} else if ( dynamic_cast<const ast::BasicType *>(type2) ) {
-			result = type2;
-		}
-	}
+		if ( enumInst->base && !enumInst->base->base ) {
+			auto basicType = new ast::BasicType( ast::BasicType::UnsignedInt );
+			result = commonType( basicType, type2, tenv, need, have, open, widen);
+		}
+	}
+
+	void postvisit( const ast::EnumAttrType * ) {}
 
 	void postvisit( const ast::TraitInstType * ) {}
@@ -696,7 +660,5 @@
 	void postvisit( const ast::TypeInstType * ) {}
 
-	void postvisit( const ast::TupleType * tuple ) {
-		tryResolveWithTypedEnum( tuple );
-	}
+	void postvisit( const ast::TupleType * tuple ) {}
 
 	void postvisit( const ast::VarArgsType * ) {}
@@ -715,8 +677,5 @@
 		} else if ( const ast::EnumInstType * enumInst = dynamic_cast< const ast::EnumInstType * >( type2 ) ) {
 			const ast::EnumDecl * enumDecl = enumInst->base;
-			if ( enumDecl->base ) {
-				if ( tryResolveWithTypedEnum( zero ) )
-					add_qualifiers( result, zero->qualifiers );
-			} else {
+			if ( !enumDecl->base ) {
 				if ( widen.second || zero->qualifiers <= type2->qualifiers ) {
 					result = type2;
@@ -738,9 +697,6 @@
 				ast::BasicType::SignedInt, one->qualifiers | type2->qualifiers };
 		} else if ( const ast::EnumInstType * enumInst = dynamic_cast< const ast::EnumInstType * >( type2 ) ) {
-			const ast::EnumDecl * enumBase = enumInst->base;
-			if ( enumBase->base ) {
-				if ( tryResolveWithTypedEnum( one ))
-					add_qualifiers( result, one->qualifiers );
-			} else {
+			const ast::EnumDecl * enumDecl = enumInst->base;
+			if ( !enumDecl->base ) {
 				if ( widen.second || one->qualifiers <= type2->qualifiers ) {
 					result = type2;
Index: src/ResolvExpr/ConversionCost.cc
===================================================================
--- src/ResolvExpr/ConversionCost.cc	(revision 06601401c36e6b2cf39fa38d23552cf5418850f3)
+++ src/ResolvExpr/ConversionCost.cc	(revision af746ccdf606483f8f89907b52e8b9471c72df7c)
@@ -278,17 +278,12 @@
 	if ( const ast::BasicType * dstAsBasic = dynamic_cast< const ast::BasicType * >( dst ) ) {
 		conversionCostFromBasicToBasic( basicType, dstAsBasic );
-	} 
-	else if ( const ast::EnumInstType * enumInst = dynamic_cast< const ast::EnumInstType * >( dst ) ) {
-		auto enumDecl = enumInst->base;
-		if ( enumDecl->base.get() ) {
-			// cost = costCalc( basicType, baseType, srcIsLvalue, symtab, env );
-			// cost.incUnsafe();
-			cost = Cost::infinity;
-		} else {
-            cost = Cost::unsafe;
-		}
-	} else if ( dynamic_cast< const ast::EnumPosType *>(dst) ) {
+	} else if ( dynamic_cast< const ast::EnumAttrType *>(dst) ) {
 		static ast::ptr<ast::BasicType> integer = { new ast::BasicType( ast::BasicType::SignedInt ) };
 		cost = costCalc( basicType, integer, srcIsLvalue, symtab, env );
+	} else if ( auto dstAsEnumInst = dynamic_cast< const ast::EnumInstType * >( dst ) ) {
+		if ( dstAsEnumInst->base && !dstAsEnumInst->base->base ) {
+			cost = Cost::zero;
+			cost.incUnsafe();
+		}
 	}
 }
@@ -366,5 +361,27 @@
 }
 
-void ConversionCost::postvisit( const ast::EnumInstType * ) {
+void ConversionCost::postvisit( const ast::EnumInstType * inst ) {
+	if ( inst->base && inst->base->base ) {
+		if ( auto dstAsAttr = dynamic_cast<const ast::EnumAttrType *>( dst ) ) {
+			auto instAsAttr = ast::EnumAttrType( inst, dstAsAttr->attr );
+			if ( instAsAttr.match(dstAsAttr) ) {
+				cost.incUnsafe();
+			}
+
+		} else if ( auto dstAsInst = dynamic_cast<const ast::EnumInstType *>( dst ) ) {
+			if (inst->base && dstAsInst->base) {
+				if (inst->base == dstAsInst->base) {
+					cost.incUnsafe();
+				}
+			}
+		} else {
+			auto instAsVal = ast::EnumAttrType( inst, ast::EnumAttribute::Value );
+			cost = costCalc( &instAsVal, dst, srcIsLvalue, symtab, env );
+			if ( cost < Cost::infinity ) {
+				cost.incUnsafe();
+			}
+		}
+		return;
+	} 
 	static ast::ptr<ast::BasicType> integer = { new ast::BasicType( ast::BasicType::SignedInt ) };
 	cost = costCalc( integer, dst, srcIsLvalue, symtab, env );
@@ -374,20 +391,33 @@
 }
 
-void ConversionCost::postvisit( const ast::EnumPosType * src ) {
-	if ( dynamic_cast<const ast::EnumPosType *>( dst ) ) {
-		// cost = costCalc( src->instance, dstBase->instance, srcIsLvalue, symtab, env );
-		// if ( cost < Cost::unsafe ) cost.incSafe();
-		cost = Cost::zero;
-	} else if ( auto dstBase = dynamic_cast<const ast::EnumInstType *>( dst ) ) {
-		cost = costCalc( src->instance, dstBase, srcIsLvalue, symtab, env );
-		if ( cost < Cost::unsafe ) cost.incSafe();
-	} else {
-		static ast::ptr<ast::BasicType> integer = { new ast::BasicType( ast::BasicType::SignedInt ) };
-		cost = costCalc( integer, dst, srcIsLvalue, symtab, env );
-		if ( cost < Cost::unsafe ) {
-			cost.incSafe();
-		}
-	}
-
+void ConversionCost::postvisit( const ast::EnumAttrType * src ) {
+    auto dstAsEnumAttrType = dynamic_cast<const ast::EnumAttrType *>(dst);
+    if ( src->attr == ast::EnumAttribute::Label ) {
+        if ( dstAsEnumAttrType && dstAsEnumAttrType->attr == ast::EnumAttribute::Label ) {
+            cost = costCalc( src->instance, dstAsEnumAttrType->instance, srcIsLvalue, symtab, env );
+        } 
+        // Add Conversion To String
+    } else if ( src->attr == ast::EnumAttribute::Value ) {
+        if ( dstAsEnumAttrType && dstAsEnumAttrType->attr == ast::EnumAttribute::Value) {
+            cost = costCalc( src->instance, dstAsEnumAttrType->instance, srcIsLvalue, symtab, env );
+        } else {
+            auto baseType = src->instance->base->base;
+            cost = costCalc( baseType, dst, srcIsLvalue, symtab, env );
+			if ( cost < Cost::infinity ) {
+				cost.incUnsafe();
+			}
+        }
+    } else { // ast::EnumAttribute::Posn
+        if ( auto dstBase = dynamic_cast<const ast::EnumInstType *>( dst ) ) {
+		    cost = costCalc( src->instance, dstBase, srcIsLvalue, symtab, env );
+		    if ( cost < Cost::unsafe ) cost.incSafe();
+	    } else {
+		    static ast::ptr<ast::BasicType> integer = { new ast::BasicType( ast::BasicType::SignedInt ) };
+		    cost = costCalc( integer, dst, srcIsLvalue, symtab, env );
+		    if ( cost < Cost::unsafe ) {
+			    cost.incSafe();
+		    }
+	    }
+    }
 }
 
@@ -466,4 +496,9 @@
 		cost.incSafe( maxIntCost + 2 );
 		// assuming 0p is supposed to be used for pointers?
+	} else if ( auto dstAsEnumInst = dynamic_cast< const ast::EnumInstType * >( dst ) ) {
+		if ( dstAsEnumInst->base && !dstAsEnumInst->base->base ) {
+			cost = Cost::zero;
+			cost.incUnsafe();
+		}
 	}
 }
@@ -483,4 +518,9 @@
 			cost.incSign( signMatrix[ ast::BasicType::SignedInt ][ dstAsBasic->kind ] );
 		}
+	} else if ( auto dstAsEnumInst = dynamic_cast< const ast::EnumInstType * >( dst ) ) {
+		if ( dstAsEnumInst->base && !dstAsEnumInst->base->base ) {
+			cost = Cost::zero;
+			cost.incUnsafe();
+		}
 	}
 }
Index: src/ResolvExpr/ConversionCost.h
===================================================================
--- src/ResolvExpr/ConversionCost.h	(revision 06601401c36e6b2cf39fa38d23552cf5418850f3)
+++ src/ResolvExpr/ConversionCost.h	(revision af746ccdf606483f8f89907b52e8b9471c72df7c)
@@ -72,5 +72,5 @@
 	void postvisit( const ast::ZeroType * zeroType );
 	void postvisit( const ast::OneType * oneType );
-	void postvisit( const ast::EnumPosType * posType );
+	void postvisit( const ast::EnumAttrType * posType );
 private:
 	// refactor for code resue
Index: src/ResolvExpr/Unify.cc
===================================================================
--- src/ResolvExpr/Unify.cc	(revision 06601401c36e6b2cf39fa38d23552cf5418850f3)
+++ src/ResolvExpr/Unify.cc	(revision af746ccdf606483f8f89907b52e8b9471c72df7c)
@@ -274,6 +274,8 @@
 		void previsit( const ast::Node * ) { visit_children = false; }
 
-		void postvisit( const ast::VoidType * ) {
-			result = dynamic_cast< const ast::VoidType * >( type2 );
+		void postvisit( const ast::VoidType * vt) {
+			result = dynamic_cast< const ast::VoidType * >( type2 )
+				|| tryToUnifyWithEnumValue(vt, type2, tenv, need, have, open, noWiden());
+			;
 		}
 
@@ -282,4 +284,5 @@
 				result = basic->kind == basic2->kind;
 			}
+			result = result || tryToUnifyWithEnumValue(basic, type2, tenv, need, have, open, noWiden());
 		}
 
@@ -290,4 +293,5 @@
 					noWiden());
 			}
+			result = result || tryToUnifyWithEnumValue(pointer, type2, tenv, need, have, open, noWiden());
 		}
 
@@ -307,5 +311,6 @@
 
 			result = unifyExact(
-				array->base, array2->base, tenv, need, have, open, noWiden());
+				array->base, array2->base, tenv, need, have, open, noWiden())
+				|| tryToUnifyWithEnumValue(array, type2, tenv, need, have, open, noWiden());
 		}
 
@@ -399,4 +404,18 @@
 		}
 
+		bool tryToUnifyWithEnumValue( const ast::Type * type1, const ast::Type * type2, ast::TypeEnvironment & env,
+			ast::AssertionSet & need, ast::AssertionSet & have, const ast::OpenVarSet & open,
+			WidenMode widen) {
+			if ( auto attrType2 = dynamic_cast<const ast::EnumAttrType *>(type2)) {
+				if (attrType2->attr == ast::EnumAttribute::Value) {
+					return unifyExact( type1, attrType2->instance->base->base, env, need, have, open,
+						widen);
+				} else if (attrType2->attr == ast::EnumAttribute::Posn) {
+					return unifyExact( type1, attrType2->instance, env, need, have, open, widen );
+				}
+			}
+			return false;
+		}
+
 	public:
 		void postvisit( const ast::FunctionType * func ) {
@@ -507,25 +526,29 @@
 		void postvisit( const ast::StructInstType * aggrType ) {
 			handleGenericRefType( aggrType, type2 );
+			result = result || tryToUnifyWithEnumValue(aggrType, type2, tenv, need, have, open, noWiden());
 		}
 
 		void postvisit( const ast::UnionInstType * aggrType ) {
 			handleGenericRefType( aggrType, type2 );
+			result = result || tryToUnifyWithEnumValue(aggrType, type2, tenv, need, have, open, noWiden());
 		}
 
 		void postvisit( const ast::EnumInstType * aggrType ) {
 			handleRefType( aggrType, type2 );
-		}
-
-		void postvisit( const ast::EnumPosType * posType ) {
+			result = result || tryToUnifyWithEnumValue(aggrType, type2, tenv, need, have, open, noWiden());
+		}
+
+		void postvisit( const ast::EnumAttrType * enumAttr ) {
 			// Lazy approach for now
-			auto otherPos = dynamic_cast< const ast::EnumPosType *>(type2);
-			if ( otherPos ) {
-				if ( otherPos->instance->base->name == posType->instance->base->name )
-					result = otherPos;
-			}
+			if ( auto otherPos = dynamic_cast< const ast::EnumAttrType *>(type2) ) {
+			    if ( enumAttr->match(otherPos) ) {
+				    result = otherPos;
+			    }
+            }  
 		}
 
 		void postvisit( const ast::TraitInstType * aggrType ) {
 			handleRefType( aggrType, type2 );
+			result = result || tryToUnifyWithEnumValue(aggrType, type2, tenv, need, have, open, noWiden());
 		}
 
@@ -536,4 +559,5 @@
 				this->result = otherInst;
 			}
+			result = result || tryToUnifyWithEnumValue(typeInst, type2, tenv, need, have, open, noWiden());
 		}
 
@@ -610,17 +634,21 @@
 			auto types2 = flatten( flat2 );
 
-			result = unifyList( types, types2, tenv, need, have, open );
-		}
-
-		void postvisit( const ast::VarArgsType * ) {
-			result = dynamic_cast< const ast::VarArgsType * >( type2 );
-		}
-
-		void postvisit( const ast::ZeroType * ) {
-			result = dynamic_cast< const ast::ZeroType * >( type2 );
-		}
-
-		void postvisit( const ast::OneType * ) {
-			result = dynamic_cast< const ast::OneType * >( type2 );
+			result = unifyList( types, types2, tenv, need, have, open )
+				|| tryToUnifyWithEnumValue(tuple, type2, tenv, need, have, open, noWiden());
+		}
+
+		void postvisit( const ast::VarArgsType * vat) {
+			result = dynamic_cast< const ast::VarArgsType * >( type2 )
+				|| tryToUnifyWithEnumValue(vat, type2, tenv, need, have, open, noWiden());
+		}
+
+		void postvisit( const ast::ZeroType * zt) {
+			result = dynamic_cast< const ast::ZeroType * >( type2 )
+				|| tryToUnifyWithEnumValue(zt, type2, tenv, need, have, open, noWiden());
+		}
+
+		void postvisit( const ast::OneType * ot) {
+			result = dynamic_cast< const ast::OneType * >( type2 )
+				|| tryToUnifyWithEnumValue(ot, type2, tenv, need, have, open, noWiden());
 		}
 	};
