Index: src/AST/Convert.cpp
===================================================================
--- src/AST/Convert.cpp	(revision 207c733028dc24fd806488429df8d9fc295a45e2)
+++ src/AST/Convert.cpp	(revision 4ef08f76a55ae935c3aff3e628469cb6618b8ca8)
@@ -705,5 +705,6 @@
 			new KeywordCastExpr(
 				get<Expression>().accept1(node->arg),
-				castTarget
+				castTarget,
+				{node->concrete_target.field, node->concrete_target.getter}
 			)
 		);
@@ -2087,5 +2088,6 @@
 				old->location,
 				GET_ACCEPT_1(arg, Expr),
-				castTarget
+				castTarget,
+				{old->concrete_target.field, old->concrete_target.getter}
 			)
 		);
Index: src/AST/Expr.hpp
===================================================================
--- src/AST/Expr.hpp	(revision 207c733028dc24fd806488429df8d9fc295a45e2)
+++ src/AST/Expr.hpp	(revision 4ef08f76a55ae935c3aff3e628469cb6618b8ca8)
@@ -312,8 +312,20 @@
 public:
 	ptr<Expr> arg;
+	struct Concrete {
+		std::string field;
+		std::string getter;
+
+		Concrete() = default;
+		Concrete(const Concrete &) = default;
+	};
 	ast::AggregateDecl::Aggregate target;
+	Concrete concrete_target;
+
 
 	KeywordCastExpr( const CodeLocation & loc, const Expr * a, ast::AggregateDecl::Aggregate t )
 	: Expr( loc ), arg( a ), target( t ) {}
+
+	KeywordCastExpr( const CodeLocation & loc, const Expr * a, ast::AggregateDecl::Aggregate t, const Concrete & ct )
+	: Expr( loc ), arg( a ), target( t ), concrete_target( ct ) {}
 
 	/// Get a name for the target type
Index: src/ResolvExpr/CandidateFinder.cpp
===================================================================
--- src/ResolvExpr/CandidateFinder.cpp	(revision 207c733028dc24fd806488429df8d9fc295a45e2)
+++ src/ResolvExpr/CandidateFinder.cpp	(revision 4ef08f76a55ae935c3aff3e628469cb6618b8ca8)
@@ -1089,4 +1089,59 @@
 		}
 
+		void postvisit( const ast::KeywordCastExpr * castExpr ) {
+			const auto & loc = castExpr->location;
+			assertf( castExpr->result, "Cast target should have been set in Validate." );
+			auto ref = castExpr->result.strict_as<ast::ReferenceType>();
+			auto inst = ref->base.strict_as<ast::StructInstType>();
+			auto target = inst->base.get();
+
+			CandidateFinder finder{ symtab, tenv };
+
+			auto pick_alternatives = [target, this](CandidateList & found, bool expect_ref) {
+				for(auto & cand : found) {
+					const ast::Type * expr = cand->expr->result.get();
+					if(expect_ref) {
+						auto res = dynamic_cast<const ast::ReferenceType*>(expr);
+						if(!res) { continue; }
+						expr = res->base.get();
+					}
+
+					if(auto insttype = dynamic_cast<const ast::TypeInstType*>(expr)) {
+						auto td = cand->env.lookup(insttype->name);
+						if(!td) { continue; }
+						expr = td->bound.get();
+					}
+
+					if(auto base = dynamic_cast<const ast::StructInstType*>(expr)) {
+						if(base->base == target) {
+							candidates.push_back( std::move(cand) );
+							reason.code = NoReason;
+						}
+					}
+				}
+			};
+
+			try {
+				// Attempt 1 : turn (thread&)X into ($thread&)X.__thrd
+				// Clone is purely for memory management
+				std::unique_ptr<const ast::Expr> tech1 { new ast::UntypedMemberExpr(loc, new ast::NameExpr(loc, castExpr->concrete_target.field), castExpr->arg) };
+
+				// don't prune here, since it's guaranteed all alternatives will have the same type
+				finder.find( tech1.get(), ResolvMode::withoutPrune() );
+				pick_alternatives(finder.candidates, false);
+
+				return;
+			} catch(SemanticErrorException & ) {}
+
+			// Fallback : turn (thread&)X into ($thread&)get_thread(X)
+			std::unique_ptr<const ast::Expr> fallback { ast::UntypedExpr::createDeref(loc,  new ast::UntypedExpr(loc, new ast::NameExpr(loc, castExpr->concrete_target.getter), { castExpr->arg })) };
+			// don't prune here, since it's guaranteed all alternatives will have the same type
+			finder.find( fallback.get(), ResolvMode::withoutPrune() );
+
+			pick_alternatives(finder.candidates, true);
+
+			// Whatever happens here, we have no more fallbacks
+		}
+
 		void postvisit( const ast::UntypedMemberExpr * memberExpr ) {
 			CandidateFinder aggFinder{ symtab, tenv };
Index: src/SynTree/Expression.cc
===================================================================
--- src/SynTree/Expression.cc	(revision 207c733028dc24fd806488429df8d9fc295a45e2)
+++ src/SynTree/Expression.cc	(revision 4ef08f76a55ae935c3aff3e628469cb6618b8ca8)
@@ -302,9 +302,8 @@
 }
 
-KeywordCastExpr::KeywordCastExpr( Expression * arg, AggregateDecl::Aggregate target ) : Expression(), arg(arg), target( target ) {
-}
-
-KeywordCastExpr::KeywordCastExpr( const KeywordCastExpr & other ) : Expression( other ), arg( maybeClone( other.arg ) ), target( other.target ) {
-}
+KeywordCastExpr::KeywordCastExpr( Expression * arg, AggregateDecl::Aggregate target ) : Expression(), arg(arg), target( target ) {}
+KeywordCastExpr::KeywordCastExpr( Expression * arg, AggregateDecl::Aggregate target, const KeywordCastExpr::Concrete & concrete_target ) : Expression(), arg(arg), target( target ), concrete_target(concrete_target) {}
+
+KeywordCastExpr::KeywordCastExpr( const KeywordCastExpr & other ) : Expression( other ), arg( maybeClone( other.arg ) ), target( other.target ) {}
 
 KeywordCastExpr::~KeywordCastExpr() {
Index: src/SynTree/Expression.h
===================================================================
--- src/SynTree/Expression.h	(revision 207c733028dc24fd806488429df8d9fc295a45e2)
+++ src/SynTree/Expression.h	(revision 4ef08f76a55ae935c3aff3e628469cb6618b8ca8)
@@ -248,4 +248,5 @@
 
 	KeywordCastExpr( Expression * arg, AggregateDecl::Aggregate target );
+	KeywordCastExpr( Expression * arg, AggregateDecl::Aggregate target, const Concrete & concrete_target );
 	KeywordCastExpr( const KeywordCastExpr & other );
 	virtual ~KeywordCastExpr();
