Index: src/AST/Convert.cpp
===================================================================
--- src/AST/Convert.cpp	(revision b3a0df6550f58a1a91e1acf2905fbb0a18cad167)
+++ src/AST/Convert.cpp	(revision 72a3aff1a5539f7902f2fb2ec6468b2cd5fec852)
@@ -1217,5 +1217,4 @@
 
 	const ast::Type * postvisit( const ast::BaseInstType * old, ReferenceToType * ty ) {
-		ty->forall = get<TypeDecl>().acceptL( old->forall );
 		ty->parameters = get<Expression>().acceptL( old->params );
 		ty->hoistType = old->hoistType;
@@ -2616,5 +2615,4 @@
 
 	void postvisit( const ReferenceToType * old, ast::BaseInstType * ty ) {
-		ty->forall = GET_ACCEPT_V( forall, TypeDecl );
 		ty->params = GET_ACCEPT_V( parameters, Expr );
 		ty->hoistType = old->hoistType;
Index: src/AST/ForallSubstitutor.hpp
===================================================================
--- src/AST/ForallSubstitutor.hpp	(revision b3a0df6550f58a1a91e1acf2905fbb0a18cad167)
+++ src/AST/ForallSubstitutor.hpp	(revision 72a3aff1a5539f7902f2fb2ec6468b2cd5fec852)
@@ -29,5 +29,5 @@
 	
 	/// Make new forall-list clone
-	ParameterizedType::ForallList operator() ( const ParameterizedType::ForallList & o ) {
+	FunctionType::ForallList operator() ( const FunctionType::ForallList & o ) {
 		return subs.clone( o, *visitor );
 	}
Index: src/AST/Pass.hpp
===================================================================
--- src/AST/Pass.hpp	(revision b3a0df6550f58a1a91e1acf2905fbb0a18cad167)
+++ src/AST/Pass.hpp	(revision 72a3aff1a5539f7902f2fb2ec6468b2cd5fec852)
@@ -287,9 +287,9 @@
 	/// Internal RAII guard for forall substitutions
 	struct guard_forall_subs {
-		guard_forall_subs( Pass<core_t> & pass, const ParameterizedType * type )
+		guard_forall_subs( Pass<core_t> & pass, const FunctionType * type )
 		: pass( pass ), type( type ) { __pass::forall::enter(pass.core, 0, type ); }
 		~guard_forall_subs()         { __pass::forall::leave(pass.core, 0, type ); }
 		Pass<core_t> & pass;
-		const ParameterizedType * type;
+		const FunctionType * type;
 	};
 
Index: src/AST/Pass.impl.hpp
===================================================================
--- src/AST/Pass.impl.hpp	(revision b3a0df6550f58a1a91e1acf2905fbb0a18cad167)
+++ src/AST/Pass.impl.hpp	(revision 72a3aff1a5539f7902f2fb2ec6468b2cd5fec852)
@@ -1777,6 +1777,4 @@
 	VISIT({
 		guard_symtab guard { *this };
-		guard_forall_subs forall_guard { *this, node };
-		mutate_forall( node );
 		maybe_accept( node, &StructInstType::params );
 	})
@@ -1795,6 +1793,4 @@
 	VISIT({
 		guard_symtab guard { *this };
-		guard_forall_subs forall_guard { *this, node };
-		mutate_forall( node );
 		maybe_accept( node, &UnionInstType::params );
 	})
@@ -1810,6 +1806,4 @@
 
 	VISIT({
-		guard_forall_subs forall_guard { *this, node };
-		mutate_forall( node );
 		maybe_accept( node, &EnumInstType::params );
 	})
@@ -1825,6 +1819,4 @@
 
 	VISIT({
-		guard_forall_subs forall_guard { *this, node };
-		mutate_forall( node );
 		maybe_accept( node, &TraitInstType::params );
 	})
@@ -1841,6 +1833,4 @@
 	VISIT(
 		{
-			guard_forall_subs forall_guard { *this, node };
-			mutate_forall( node );
 			maybe_accept( node, &TypeInstType::params );
 		}
Index: src/AST/Pass.proto.hpp
===================================================================
--- src/AST/Pass.proto.hpp	(revision b3a0df6550f58a1a91e1acf2905fbb0a18cad167)
+++ src/AST/Pass.proto.hpp	(revision 72a3aff1a5539f7902f2fb2ec6468b2cd5fec852)
@@ -396,5 +396,5 @@
 		// Some simple scoping rules
 		template<typename core_t>
-		static inline auto enter( core_t & core, int, const ast::ParameterizedType * type )
+		static inline auto enter( core_t & core, int, const ast::FunctionType * type )
 		-> decltype( core.subs, void() ) {
 			if ( ! type->forall.empty() ) core.subs.beginScope();
@@ -402,8 +402,8 @@
 
 		template<typename core_t>
-		static inline auto enter( core_t &, long, const ast::ParameterizedType * ) {}
-
-		template<typename core_t>
-		static inline auto leave( core_t & core, int, const ast::ParameterizedType * type )
+		static inline auto enter( core_t &, long, const ast::FunctionType * ) {}
+
+		template<typename core_t>
+		static inline auto leave( core_t & core, int, const ast::FunctionType * type )
 		-> decltype( core.subs, void() ) {
 			if ( ! type->forall.empty() ) { core.subs.endScope(); }
@@ -411,5 +411,5 @@
 
 		template<typename core_t>
-		static inline auto leave( core_t &, long, const ast::ParameterizedType * ) {}
+		static inline auto leave( core_t &, long, const ast::FunctionType * ) {}
 
 		// Get the substitution table, if present
Index: src/AST/Print.cpp
===================================================================
--- src/AST/Print.cpp	(revision b3a0df6550f58a1a91e1acf2905fbb0a18cad167)
+++ src/AST/Print.cpp	(revision 72a3aff1a5539f7902f2fb2ec6468b2cd5fec852)
@@ -146,5 +146,5 @@
 	}
 
-	void print( const ast::ParameterizedType::ForallList & forall ) {
+	void print( const ast::FunctionType::ForallList & forall ) {
 		if ( forall.empty() ) return;
 		os << "forall" << endl;
@@ -259,5 +259,5 @@
 	}
 
-	void preprint( const ast::ParameterizedType * node ) {
+	void preprint( const ast::FunctionType * node ) {
 		print( node->forall );
 		print( node->qualifiers );
@@ -265,5 +265,4 @@
 
 	void preprint( const ast::BaseInstType * node ) {
-		print( node->forall );
 		print( node->attributes );
 		print( node->qualifiers );
Index: src/AST/Type.cpp
===================================================================
--- src/AST/Type.cpp	(revision b3a0df6550f58a1a91e1acf2905fbb0a18cad167)
+++ src/AST/Type.cpp	(revision 72a3aff1a5539f7902f2fb2ec6468b2cd5fec852)
@@ -94,6 +94,6 @@
 // --- ParameterizedType
 
-void ParameterizedType::initWithSub(
-	const ParameterizedType & o, Pass< ForallSubstitutor > & sub
+void FunctionType::initWithSub(
+	const FunctionType & o, Pass< ForallSubstitutor > & sub
 ) {
 	forall = sub.core( o.forall );
@@ -104,5 +104,5 @@
 
 FunctionType::FunctionType( const FunctionType & o )
-: ParameterizedType( o.qualifiers, copy( o.attributes ) ), returns(), params(),
+: Type( o.qualifiers, copy( o.attributes ) ), returns(), params(),
   isVarArgs( o.isVarArgs ) {
 	Pass< ForallSubstitutor > sub;
@@ -125,18 +125,4 @@
 }
 
-// --- BaseInstType
-
-void BaseInstType::initWithSub( const BaseInstType & o, Pass< ForallSubstitutor > & sub ) {
-	ParameterizedType::initWithSub( o, sub ); // initialize substitution
-	params = sub.core( o.params );            // apply to parameters
-}
-
-BaseInstType::BaseInstType( const BaseInstType & o )
-: ParameterizedType( o.qualifiers, copy( o.attributes ) ), params(), name( o.name ),
-  hoistType( o.hoistType ) {
-	Pass< ForallSubstitutor > sub;
-	initWithSub( o, sub );
-}
-
 std::vector<readonly<Decl>> BaseInstType::lookup( const std::string& name ) const {
 	assertf( aggr(), "Must have aggregate to perform lookup" );
@@ -176,13 +162,4 @@
 	const TraitDecl * b, CV::Qualifiers q, std::vector<ptr<Attribute>>&& as )
 : BaseInstType( b->name, q, move(as) ), base( b ) {}
-
-// --- TypeInstType
-
-TypeInstType::TypeInstType( const TypeInstType & o )
-: BaseInstType( o.name, o.qualifiers, copy( o.attributes ) ), base(), kind( o.kind ) {
-	Pass< ForallSubstitutor > sub;
-	initWithSub( o, sub );      // initialize substitution
-	base = sub.core( o.base );  // apply to base type
-}
 
 void TypeInstType::set_base( const TypeDecl * b ) {
Index: src/AST/Type.hpp
===================================================================
--- src/AST/Type.hpp	(revision b3a0df6550f58a1a91e1acf2905fbb0a18cad167)
+++ src/AST/Type.hpp	(revision 72a3aff1a5539f7902f2fb2ec6468b2cd5fec852)
@@ -267,39 +267,16 @@
 };
 
-/// Base type for potentially forall-qualified types
-class ParameterizedType : public Type {
-protected:
-	/// initializes forall with substitutor
-	void initWithSub( const ParameterizedType & o, Pass< ForallSubstitutor > & sub );
-public:
-	using ForallList = std::vector<ptr<TypeDecl>>;
-
-	ForallList forall;
-
-	ParameterizedType( ForallList&& fs = {}, CV::Qualifiers q = {},
-		std::vector<ptr<Attribute>> && as = {} )
-	: Type(q, std::move(as)), forall(std::move(fs)) {}
-
-	ParameterizedType( CV::Qualifiers q, std::vector<ptr<Attribute>> && as = {} )
-	: Type(q, std::move(as)), forall() {}
-
-	// enforce use of ForallSubstitutor to copy parameterized type
-	ParameterizedType( const ParameterizedType & ) = delete;
-
-	ParameterizedType( ParameterizedType && ) = default;
-
-	// no need to change destructor, and operator= deleted in Node
-
-private:
-	virtual ParameterizedType * clone() const override = 0;
-	MUTATE_FRIEND
-};
-
 /// Function variable arguments flag
 enum ArgumentFlag { FixedArgs, VariableArgs };
 
 /// Type of a function `[R1, R2](*)(P1, P2, P3)`
-class FunctionType final : public ParameterizedType {
-public:
+class FunctionType final : public Type {
+	protected:
+	/// initializes forall with substitutor
+	void initWithSub( const FunctionType & o, Pass< ForallSubstitutor > & sub );
+public:
+	using ForallList = std::vector<ptr<TypeDecl>>;
+	ForallList forall;
+
 	std::vector<ptr<Type>> returns;
 	std::vector<ptr<Type>> params;
@@ -313,5 +290,5 @@
 
 	FunctionType( ArgumentFlag va = FixedArgs, CV::Qualifiers q = {} )
-	: ParameterizedType(q), returns(), params(), isVarArgs(va) {}
+	: Type(q), returns(), params(), isVarArgs(va) {}
 
 	FunctionType( const FunctionType & o );
@@ -329,8 +306,5 @@
 
 /// base class for types that refer to types declared elsewhere (aggregates and typedefs)
-class BaseInstType : public ParameterizedType {
-protected:
-	/// Initializes forall and parameters based on substitutor
-	void initWithSub( const BaseInstType & o, Pass< ForallSubstitutor > & sub );
+class BaseInstType : public Type {
 public:
 	std::vector<ptr<Expr>> params;
@@ -340,12 +314,12 @@
 	BaseInstType(
 		const std::string& n, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} )
-	: ParameterizedType(q, std::move(as)), params(), name(n) {}
+	: Type(q, std::move(as)), params(), name(n) {}
 
 	BaseInstType(
 		const std::string& n, std::vector<ptr<Expr>> && params,
 		CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} )
-	: ParameterizedType(q, std::move(as)), params(std::move(params)), name(n) {}
-
-	BaseInstType( const BaseInstType & o );
+	: Type(q, std::move(as)), params(std::move(params)), name(n) {}
+
+	BaseInstType( const BaseInstType & o ) = default;
 
 	/// Gets aggregate declaration this type refers to
@@ -433,5 +407,5 @@
 	: BaseInstType( n, q, std::move(as) ), base(), kind( k ) {}
 
-	TypeInstType( const TypeInstType & o );
+	TypeInstType( const TypeInstType & o ) = default;
 
 	/// sets `base`, updating `kind` correctly
Index: src/AST/TypeEnvironment.cpp
===================================================================
--- src/AST/TypeEnvironment.cpp	(revision b3a0df6550f58a1a91e1acf2905fbb0a18cad167)
+++ src/AST/TypeEnvironment.cpp	(revision 72a3aff1a5539f7902f2fb2ec6468b2cd5fec852)
@@ -105,5 +105,5 @@
 }
 
-void TypeEnvironment::add( const ParameterizedType::ForallList & tyDecls ) {
+void TypeEnvironment::add( const FunctionType::ForallList & tyDecls ) {
 	for ( const TypeDecl * tyDecl : tyDecls ) {
 		env.emplace_back( tyDecl );
Index: src/AST/TypeEnvironment.hpp
===================================================================
--- src/AST/TypeEnvironment.hpp	(revision b3a0df6550f58a1a91e1acf2905fbb0a18cad167)
+++ src/AST/TypeEnvironment.hpp	(revision 72a3aff1a5539f7902f2fb2ec6468b2cd5fec852)
@@ -134,5 +134,5 @@
 
 	/// Add a new equivalence class for each type variable
-	void add( const ParameterizedType::ForallList & tyDecls );
+	void add( const FunctionType::ForallList & tyDecls );
 
 	/// Add a new equivalence class for each branch of the substitution, checking for conflicts
Index: src/AST/TypeSubstitution.cpp
===================================================================
--- src/AST/TypeSubstitution.cpp	(revision b3a0df6550f58a1a91e1acf2905fbb0a18cad167)
+++ src/AST/TypeSubstitution.cpp	(revision 72a3aff1a5539f7902f2fb2ec6468b2cd5fec852)
@@ -166,5 +166,5 @@
 }
 
-void TypeSubstitution::Substituter::previsit( const ParameterizedType * ptype ) {
+void TypeSubstitution::Substituter::previsit( const FunctionType * ptype ) {
 	GuardValue( boundVars );
 	// bind type variables from forall-qualifiers
@@ -180,7 +180,4 @@
 	// bind type variables from forall-qualifiers
 	if ( freeOnly ) {
-		for ( const TypeDecl * tyvar : type->forall ) {
-			boundVars.insert( tyvar->name );
-		} // for
 		// bind type variables from generic type instantiations
 		if ( auto decl = type->aggr() ) {
Index: src/AST/TypeSubstitution.hpp
===================================================================
--- src/AST/TypeSubstitution.hpp	(revision b3a0df6550f58a1a91e1acf2905fbb0a18cad167)
+++ src/AST/TypeSubstitution.hpp	(revision 72a3aff1a5539f7902f2fb2ec6468b2cd5fec852)
@@ -167,5 +167,5 @@
 
 		/// Records type variable bindings from forall-statements
-		void previsit( const ParameterizedType * type );
+		void previsit( const FunctionType * type );
 		/// Records type variable bindings from forall-statements and instantiations of generic types
 		void handleAggregateType( const BaseInstType * type );
