diff --git a/src/main/scala/inox/solvers/unrolling/DatatypeTemplates.scala b/src/main/scala/inox/solvers/unrolling/DatatypeTemplates.scala
index c2ba6409aa5b735d5955fa1aef78cb6ba7dea980..8f33f9bb39f7fd9ad5a685e9d22556ec1bd138d5 100644
--- a/src/main/scala/inox/solvers/unrolling/DatatypeTemplates.scala
+++ b/src/main/scala/inox/solvers/unrolling/DatatypeTemplates.scala
@@ -29,29 +29,46 @@ trait DatatypeTemplates { self: Templates =>
 
   type Functions = Set[(Encoded, FunctionType, Encoded)]
 
+  /** Represents the kind of datatype a given template is associated to. */
   sealed abstract class TypeInfo {
     def getType: Type = this match {
       case SortInfo(tsort) => tsort.toType
       case SetInfo(base) => SetType(base)
       case BagInfo(base) => BagType(base)
+      case MapInfo(from, to) => MapType(from, to)
     }
   }
 
   case class SortInfo(tsort: TypedADTSort) extends TypeInfo
   case class SetInfo(base: Type) extends TypeInfo
   case class BagInfo(base: Type) extends TypeInfo
+  case class MapInfo(from: Type, to: Type) extends TypeInfo
+ 
+  /** Represents the kind of instantiator (@see [[TypesTemplate]]) a given
+    * template info is associated to. */
+  sealed abstract class TemplateInstantiator {
+    def substitute(substituter: Encoded => Encoded): TemplateInstantiator = this match {
+      case Datatype => Datatype
+      case Capture(encoded, tpe) => Capture(substituter(encoded), tpe)
+      case Invariant => Invariant
+    }
+  }
+
+  case object Datatype extends TemplateInstantiator
+  case class Capture(encoded: Encoded, tpe: FunctionType) extends TemplateInstantiator
+  case object Invariant extends TemplateInstantiator
 
   /** Represents a type unfolding of a free variable (or input) in the unfolding procedure */
-  case class TemplateTypeInfo(info: TypeInfo, arg: Encoded, outer: Option[(Encoded, FunctionType)]) {
+  case class TemplateTypeInfo(info: TypeInfo, arg: Encoded, instantiator: TemplateInstantiator) {
     override def toString: String =
-      info + "(" + asString(arg) + ")" + (outer match {
-        case Some((f, tpe)) => " in " + asString(f)
-        case None => ""
+      info + "(" + asString(arg) + ")" + (instantiator match {
+        case Capture(f, tpe) => " in " + asString(f)
+        case _ => ""
       })
 
     def substitute(substituter: Encoded => Encoded): TemplateTypeInfo = copy(
       arg = substituter(arg),
-      outer = outer.map(p => (substituter(p._1), p._2))
+      instantiator = instantiator.substitute(substituter)
     )
   }
 
@@ -65,15 +82,21 @@ trait DatatypeTemplates { self: Templates =>
     CaptureTemplate(arg._2, container._2).instantiate(start, container._1, arg._1)
   }
 
+  /** Sets up the relevant unfolding procedure for datatype invariant instantiation. */
+  def unrollInvariant(start: Encoded, sym: Encoded, tpe: Type): Clauses = {
+    InvariantTemplate(tpe).instantiate(start, sym)
+  }
+
   /** Base trait for datatype unfolding template generators.
     *
     * This trait provides a useful interface for building datatype unfolding
     * templates. The interesting override points are:
     *
-    * - [[unrollType]]:
+    * - [[unroll]]:
     *   determines whether a given type requires unfolding.
-    *   @see [[$DatatypeTemplate.unrollType]]
-    *   @see [[$CaptureTemplate.unrollType]]
+    *   @see [[ADTUnrolling.unroll]]
+    *   @see [[FunctionUnrolling.unroll]]
+    *   @see [[FullTemplateGenerator.unroll]]
     *
     * - [[Builder.rec]]:
     *   can be overriden to provide finer controll of what clauses should be generated during
@@ -88,51 +111,16 @@ trait DatatypeTemplates { self: Templates =>
     * @see [[$CaptureTemplate]]
     */
   sealed protected trait TemplateGenerator {
-    private val checking: MutableSet[TypedADTDefinition] = MutableSet.empty
-    private val unrollCache: MutableMap[Type, Boolean] = MutableMap.empty
-
-    /** Determines whether a given [[Type]] needs to be considered during ADT unfolding.
-      * 
-      * This function DOES NOT correspond to an override point (hence the `final` modifier.
-      * One should look at [[unrollType]] to change the behavior of [[unroll]].
-      */
-    final def unroll(tpe: Type): Boolean = unrollCache.getOrElseUpdate(tpe, {
-      unrollType(tpe) || (tpe match {
-        case adt: ADTType => adt.getADT match {
-          case tadt if checking(tadt.root) => false
-          case tadt =>
-            checking += tadt.root
-            val constructors = tadt.root match {
-              case tsort: TypedADTSort => tsort.constructors
-              case tcons: TypedADTConstructor => Seq(tcons)
-            }
+    /** Determines whether a given [[Type]] needs to be considered during ADT unfolding. */
+    def unroll(tpe: Type): Boolean
 
-            constructors.exists(c => c.fieldsTypes.exists(unroll))
-        }
-
-        case BooleanType | UnitType | CharType | IntegerType |
-             RealType | StringType | (_: BVType) | (_: TypeParameter) => false
-
-        case (_: FunctionType) | (_: BagType) | (_: SetType) => true
-
-        case NAryType(tpes, _) => tpes.exists(unroll)
-      })
-    })
-
-    /** Override point to determine whether a given type should be unfolded.
-      *
-      * This methods shouldn't be recursive as the ADT traversal already takes place
-      * within the [[unroll]] method.
-      *
-      * By default, returns `false`.
-      */
-    protected def unrollType(tpe: Type): Boolean = false
-
-    /** Stateful template generating class. Provides the [[rec]] override point so that
+    /** Stateful template generating trait. Provides the [[rec]] override point so that
       * subclasses of [[TemplateGenerator]] can override [[rec]] while still using
       * stateful clause generation.
       */
-    protected class Builder(tpe: Type) {
+    protected trait Builder {
+      val tpe: Type
+
       protected val v = Variable(FreshIdentifier("x", true), tpe)
       val pathVar = Variable(FreshIdentifier("b", true), BooleanType)
       val (idT, pathVarT) = (encodeSymbol(v), encodeSymbol(pathVar))
@@ -163,13 +151,9 @@ trait DatatypeTemplates { self: Templates =>
         tpes += pathVar -> (tpes.getOrElse(pathVar, Set.empty) + (info -> arg))
       }
 
-      private var functions = Map[Variable, Set[Expr]]()
-      @inline protected def storeFunction(pathVar: Variable, expr: Expr): Unit = {
-        functions += pathVar -> (functions.getOrElse(pathVar, Set.empty) + expr)
-      }
-
       protected case class RecursionState(
         recurseSort: Boolean, // visit sort children
+        recurseMap: Boolean,  // unroll map definition
         recurseSet: Boolean,  // unroll set definition
         recurseBag: Boolean   // unroll bag definition
       )
@@ -218,8 +202,31 @@ trait DatatypeTemplates { self: Templates =>
             rec(pathVar, TupleSelect(expr, idx + 1), state)
           }
 
-        case FunctionType(_, _) =>
-          storeFunction(pathVar, expr)
+        case MapType(from, to) =>
+          val newBool: Variable = Variable(FreshIdentifier("b", true), BooleanType)
+          storeCond(pathVar, newBool)
+
+          val dfltExpr: Variable = Variable(FreshIdentifier("dlft", true), to)
+          storeExpr(dfltExpr)
+
+          iff(and(pathVar, Not(Equals(expr, FiniteMap(Seq.empty, dfltExpr, from, to)))), newBool)
+          rec(pathVar, dfltExpr, state)
+
+          if (!state.recurseMap) {
+            storeType(newBool, MapInfo(from, to), expr)
+          } else {
+            val keyExpr: Variable = Variable(FreshIdentifier("key", true), from)
+            val valExpr: Variable = Variable(FreshIdentifier("val", true), to)
+            val restExpr: Variable = Variable(FreshIdentifier("rest", true), MapType(from, to))
+            storeExpr(keyExpr)
+            storeExpr(valExpr)
+            storeExpr(restExpr)
+
+            storeGuarded(newBool, Equals(expr, MapUpdated(restExpr, keyExpr, valExpr)))
+            rec(newBool, restExpr, state.copy(recurseMap = false))
+            rec(newBool, keyExpr, state)
+            rec(newBool, valExpr, state)
+          }
 
         case SetType(base) =>
           val newBool: Variable = Variable(FreshIdentifier("b", true), BooleanType)
@@ -266,8 +273,8 @@ trait DatatypeTemplates { self: Templates =>
 
       /* Calls [[rec]] and finalizes the bookkeeping collection before returning everything
        * necessary to a template creation. */
-      lazy val (encoder, exprs, conds, tree, clauses, calls, types, funs) = {
-        rec(pathVar, v, RecursionState(true, true, true))
+      lazy val (encoder, exprs, conds, tree, clauses, calls, types) = {
+        rec(pathVar, v, RecursionState(true, true, true, true))
 
         val encoder: Expr => Encoded = mkEncoder(exprVars ++ condVars + (v -> idT) + (pathVar -> pathVarT))
 
@@ -294,12 +301,152 @@ trait DatatypeTemplates { self: Templates =>
           encoder(b) -> tps.map { case (info, expr) => (info, encoder(expr)) }
         }
 
-        val encodedFunctions: Functions = functions.flatMap { case (b, fs) =>
-          val bp = encoder(b)
-          fs.map(expr => (bp, bestRealType(expr.getType).asInstanceOf[FunctionType], encoder(expr)))
+        (encoder, exprVars, condVars, condTree, clauses, calls, encodedTypes)
+      }
+    }
+  }
+
+  /** Extends [[TemplateGenerator]] with functionalities for checking whether
+    * ADTs need to be unrolled.
+    *
+    * Note that the actual ADT unrolling takes place in [[TemplateGenerator.Builder.rec]].
+    */
+  protected trait ADTUnrolling extends TemplateGenerator {
+    private val checking: MutableSet[TypedADTDefinition] = MutableSet.empty
+
+    /** We recursively visit the ADT and its fields here to check whether we need to unroll. */
+    abstract override def unroll(tpe: Type): Boolean = tpe match {
+      case adt: ADTType => adt.getADT match {
+        case tadt if checking(tadt.root) => false
+        case tadt =>
+          checking += tadt.root
+          val constructors = tadt.root match {
+            case tsort: TypedADTSort => tsort.constructors
+            case tcons: TypedADTConstructor => Seq(tcons)
+          }
+
+          constructors.exists(c => c.fieldsTypes.exists(unroll))
+      }
+
+      case _ => super.unroll(tpe)
+    }
+  }
+
+  /** Extends [[TemplateGenerator]] with functionalities to accumulate the set
+    * of functions contained within a datastructure.
+    */
+  protected trait FunctionUnrolling extends TemplateGenerator {
+
+    /** The definition of [[unroll]] makes sure ALL functions are discovered. */
+    def unroll(tpe: Type): Boolean = tpe match {
+      case BooleanType | UnitType | CharType | IntegerType |
+           RealType | StringType | (_: BVType) | (_: TypeParameter) => false
+
+      case (_: FunctionType) | (_: BagType) | (_: SetType) => true
+
+      case NAryType(tpes, _) => tpes.exists(unroll)
+    }
+
+    /** The [[TemplateGenerator.Builder]] trait is extended to accumulate functions
+      * during the clause generation. */
+    protected trait Builder extends super.Builder {
+      private var functions = Map[Variable, Set[Expr]]()
+      @inline protected def storeFunction(pathVar: Variable, expr: Expr): Unit = {
+        functions += pathVar -> (functions.getOrElse(pathVar, Set.empty) + expr)
+      }
+
+      override protected def rec(pathVar: Variable, expr: Expr, state: RecursionState): Unit = expr.getType match {
+        case _: FunctionType => storeFunction(pathVar, expr)
+        case _ => super.rec(pathVar, expr, state)
+      }
+
+      lazy val funs: Functions = {
+        val enc = encoder // forces super to call rec()
+        functions.flatMap { case (b, fs) =>
+          val bp = enc(b)
+          fs.map(expr => (bp, bestRealType(expr.getType).asInstanceOf[FunctionType], enc(expr)))
         }.toSet
+      }
+    }
+  }
+
+  /** Template generator that ensures [[unroll]] call results are cached. */
+  protected trait CachedUnrolling extends TemplateGenerator {
+    private val unrollCache: MutableMap[Type, Boolean] = MutableMap.empty
+
+    /** Determines whether a given [[Type]] needs to be considered during ADT unfolding.
+      * 
+      * This function DOES NOT correspond to an override point (hence the `final` modifier).
+      * One should look at [[unrollType]] to change the behavior of [[unroll]].
+      */
+    abstract override final def unroll(tpe: Type): Boolean = unrollCache.getOrElseUpdate(tpe, {
+      unrollType(tpe) || super.unroll(tpe)
+    })
+
+    /** Override point to determine whether a given type should be unfolded.
+      *
+      * This methods shouldn't be recursive as the ADT traversal already takes place
+      * within the [[unroll]] method.
+      *
+      * By default, returns `false`.
+      */
+    protected def unrollType(tpe: Type): Boolean = false
+  }
+
+  /** Template generator that combines ADT unrolling and function accumulation.
+    *
+    * See [[$CaptureTemplate]] and [[$DatatypeTemplate]] for concrete examples. */
+  /*protected trait FullTemplateGenerator
+    extends TemplateGenerator
+       with FunctionUnrolling
+       with ADTUnrolling
+       with CachedUnrolling*/
+
+  /** Template generator that generates clauses for ADT invariant assertion. */
+  protected trait InvariantGenerator
+    extends TemplateGenerator
+       with ADTUnrolling
+       with CachedUnrolling {
+
+    /** ADT unfolding is required when either:
+     * 1. a constructor type is required and it has a super-type (SMT solvers
+     *    are blind to this case), or
+     * 2. the ADT type has an ADT invariant.
+     *
+     * Note that clause generation in [[Builder.rec]] MUST correspond to the types
+     * that require unfolding as defined here.
+     */
+    override protected def unrollType(tpe: Type): Boolean = tpe match {
+      case adt: ADTType => adt.getADT match {
+        case tcons: TypedADTConstructor if tcons.sort.isDefined => true
+        case tdef => tdef.hasInvariant
+      }
+      case _ => false
+    }
+
+    /** Clause generation is specialized to handle ADT constructor types that require
+      * type guards as well as ADT invariants. */
+    protected trait Builder extends super.Builder {
+      override protected def rec(pathVar: Variable, expr: Expr, state: RecursionState): Unit = expr.getType match {
+        case adt: ADTType =>
+          val tadt = adt.getADT
 
-        (encoder, exprVars, condVars, condTree, clauses, calls, encodedTypes, encodedFunctions)
+          if (tadt.hasInvariant) {
+            storeGuarded(pathVar, tadt.invariant.get.applied(Seq(expr)))
+          }
+
+          if (tadt != tadt.root) {
+            storeGuarded(pathVar, IsInstanceOf(expr, tadt.toType))
+
+            val tpe = tadt.toType
+            for (vd <- tadt.toConstructor.fields) {
+              rec(pathVar, ADTSelector(AsInstanceOf(expr, tpe), vd.id), state.copy(recurseSort = false))
+            }
+          } else {
+            super.rec(pathVar, expr, state)
+          }
+
+        case _ => super.rec(pathVar, expr, state)
       }
     }
   }
@@ -364,55 +511,17 @@ trait DatatypeTemplates { self: Templates =>
   }
 
   /** Generator for [[DatatypeTemplate]] instances. */
-  object DatatypeTemplate extends TemplateGenerator {
+  object DatatypeTemplate extends FunctionUnrolling with InvariantGenerator {
     private val cache: MutableMap[Type, DatatypeTemplate] = MutableMap.empty
 
-    /** ADT unfolding is required when either:
-     * 1. a constructor type is required and it has a super-type (SMT solvers
-     *    are blind to this case), or
-     * 2. the ADT type has an ADT invariant.
-     *
-     * Note that clause generation in [[Builder.rec]] MUST correspond to the types
-     * that require unfolding as defined here.
-     */
-    override protected def unrollType(tpe: Type): Boolean = tpe match {
-      case adt: ADTType => adt.getADT match {
-        case tcons: TypedADTConstructor if tcons.sort.isDefined => true
-        case tdef => tdef.hasInvariant
-      }
-      case _ => false
-    }
-
-    /** Clause generation is specialized to handle ADT constructor types that require
-      * type guards as well as ADT invariants. */
-    protected class Builder(tpe: Type) extends super.Builder(tpe) {
-      override protected def rec(pathVar: Variable, expr: Expr, state: RecursionState): Unit = expr.getType match {
-        case adt: ADTType =>
-          val tadt = adt.getADT
-
-          if (tadt.hasInvariant) {
-            storeGuarded(pathVar, tadt.invariant.get.applied(Seq(expr)))
-          }
-
-          if (tadt != tadt.root) {
-            storeGuarded(pathVar, IsInstanceOf(expr, tadt.toType))
-
-            val tpe = tadt.toType
-            for (vd <- tadt.toConstructor.fields) {
-              rec(pathVar, ADTSelector(AsInstanceOf(expr, tpe), vd.id), state.copy(recurseSort = false))
-            }
-          } else {
-            super.rec(pathVar, expr, state)
-          }
-
-        case _ => super.rec(pathVar, expr, state)
-      }
-    }
+    def apply(dtpe: Type): DatatypeTemplate = cache.getOrElseUpdate(dtpe, {
+      object b extends {
+        val tpe = dtpe
+      } with super[FunctionUnrolling].Builder
+        with super[InvariantGenerator].Builder
 
-    def apply(tpe: Type): DatatypeTemplate = cache.getOrElseUpdate(tpe, {
-      val b = new Builder(tpe)
       val typeBlockers: TypeBlockers = b.types.map { case (blocker, tps) =>
-        blocker -> tps.map { case (info, arg) => TemplateTypeInfo(info, arg, None) }
+        blocker -> tps.map { case (info, arg) => TemplateTypeInfo(info, arg, Datatype) }
       }
 
       new DatatypeTemplate(b.pathVar -> b.pathVarT, b.idT,
@@ -452,7 +561,11 @@ trait DatatypeTemplates { self: Templates =>
   }
 
   /** Template generator for [[CaptureTemplate]] instances. */
-  object CaptureTemplate extends TemplateGenerator {
+  object CaptureTemplate
+    extends FunctionUnrolling
+       with ADTUnrolling
+       with CachedUnrolling {
+
     private val tmplCache: MutableMap[Type, (
       (Variable, Encoded),
       Encoded,
@@ -484,9 +597,9 @@ trait DatatypeTemplates { self: Templates =>
       (na: Encoded) => mkSubstituter(Map(aT -> na))(encoded)
     })
 
-    def apply(tpe: Type, containerType: FunctionType): CaptureTemplate = cache.getOrElseUpdate(tpe -> containerType, {
-      val (ps, idT, exprVars, condVars, condTree, clauses, types, funs) = tmplCache.getOrElseUpdate(tpe, {
-        val b = new Builder(tpe)
+    def apply(dtpe: Type, containerType: FunctionType): CaptureTemplate = cache.getOrElseUpdate(dtpe -> containerType, {
+      val (ps, idT, exprVars, condVars, condTree, clauses, types, funs) = tmplCache.getOrElseUpdate(dtpe, {
+        object b extends { val tpe = dtpe } with Builder
         assert(b.calls.isEmpty, "Captured function templates shouldn't have any calls: " + b.calls)
         (b.pathVar -> b.pathVarT, b.idT, b.exprs, b.conds, b.tree, b.clauses, b.types, b.funs)
       })
@@ -496,7 +609,7 @@ trait DatatypeTemplates { self: Templates =>
       val containerT = encodeSymbol(container)
 
       val typeBlockers: TypeBlockers = types.map { case (blocker, tps) =>
-        blocker -> tps.map { case (info, arg) => TemplateTypeInfo(info, arg, Some(containerT -> ctpe)) }
+        blocker -> tps.map { case (info, arg) => TemplateTypeInfo(info, arg, Capture(containerT, ctpe)) }
       }
 
       val orderClauses = funs.map { case (blocker, tpe, f) =>
@@ -508,6 +621,49 @@ trait DatatypeTemplates { self: Templates =>
     })
   }
 
+  /** Template used to unfold adts returned from functions or maps. */
+  class InvariantTemplate private[DatatypeTemplates] (
+    val pathVar: (Variable, Encoded),
+    val argument: Encoded,
+    val exprVars: Map[Variable, Encoded],
+    val condVars: Map[Variable, Encoded],
+    val condTree: Map[Variable, Set[Variable]],
+    val clauses: Clauses,
+    val blockers: CallBlockers,
+    val types: Map[Encoded, Set[TemplateTypeInfo]]) extends TypesTemplate {
+
+    val args = Seq(argument)
+
+    def instantiate(blocker: Encoded, arg: Encoded): Clauses = {
+      instantiate(blocker, Seq(Left(arg)))
+    }
+  }
+
+  /** Extends [[TemplateGenerator]] with functionalities for checking whether
+    * tuples need to be unrolled. This trait will typically be mixed in with
+    * the [[ADTUnrolling]] trait. */
+  trait FlatUnrolling extends TemplateGenerator {
+    def unroll(tpe: Type): Boolean = tpe match {
+      case TupleType(tps) => tps.exists(unroll)
+      case _ => false
+    }
+  }
+
+  /** Template generator for [[InvariantTemplate]] instances. */
+  object InvariantTemplate extends TemplateGenerator with FlatUnrolling with InvariantGenerator {
+    private val cache: MutableMap[Type, InvariantTemplate] = MutableMap.empty
+
+    def apply(dtpe: Type): InvariantTemplate = cache.getOrElseUpdate(dtpe, {
+      object b extends { val tpe = dtpe } with Builder
+      val typeBlockers: TypeBlockers = b.types.map { case (blocker, tps) =>
+        blocker -> tps.map { case (info, arg) => TemplateTypeInfo(info, arg, Invariant) }
+      }
+
+      new InvariantTemplate(b.pathVar -> b.pathVarT, b.idT,
+        b.exprs, b.conds, b.tree, b.clauses, b.calls, typeBlockers)
+    })
+  }
+
   private[unrolling] object datatypesManager extends Manager {
     val typeInfos = new IncrementalMap[Encoded, (Int, Int, Encoded, Set[TemplateTypeInfo])]
     val lessOrder = new IncrementalMap[Encoded, Set[Encoded]].withDefaultValue(Set.empty)
@@ -547,13 +703,16 @@ trait DatatypeTemplates { self: Templates =>
       val newTypeInfos = typeBlockers.flatMap(id => typeInfos.get(id).map(id -> _))
       typeInfos --= typeBlockers
 
-      for ((blocker, (gen, _, _, tps)) <- newTypeInfos; TemplateTypeInfo(info, arg, oc) <- tps) oc match {
-        case None =>
+      for ((blocker, (gen, _, _, tps)) <- newTypeInfos; TemplateTypeInfo(info, arg, inst) <- tps) inst match {
+        case Datatype =>
           val template = DatatypeTemplate(info.getType)
           newClauses ++= template.instantiate(blocker, arg)
-        case Some((container, containerType)) =>
+        case Capture(container, containerType) =>
           val template = CaptureTemplate(info.getType, containerType)
           newClauses ++= template.instantiate(blocker, container, arg)
+        case Invariant =>
+          val template = InvariantTemplate(info.getType)
+          newClauses ++= template.instantiate(blocker, arg)
       }
 
       ctx.reporter.debug("Unrolling datatypes (" + newClauses.size + ")")
diff --git a/src/main/scala/inox/solvers/unrolling/QuantificationTemplates.scala b/src/main/scala/inox/solvers/unrolling/QuantificationTemplates.scala
index ac9635208b7abf60feb5360cc7c05abb122a1479..f30efa6cb3fd4b45bdb5f7dfb83e8fd48d175b6a 100644
--- a/src/main/scala/inox/solvers/unrolling/QuantificationTemplates.scala
+++ b/src/main/scala/inox/solvers/unrolling/QuantificationTemplates.scala
@@ -322,7 +322,19 @@ trait QuantificationTemplates { self: Templates =>
     } else {
       ctx.reporter.debug(" -> instantiating matcher " + blockers.mkString("{",",","}") + " ==> " + matcher)
       handledMatchers += relevantBlockers -> matcher
-      quantifications.flatMap(_.instantiate(relevantBlockers, matcher, defer))
+      val qClauses: Clauses = quantifications.flatMap(_.instantiate(relevantBlockers, matcher, defer))
+
+      val mClauses: Clauses = matcherKey(matcher) match {
+        case FunctionKey(tfd) =>
+          val (b, encClauses) = encodeBlockers(relevantBlockers)
+          encClauses ++ unrollInvariant(b, matcher.encoded, tfd.returnType)
+        case TypeKey(MapType(_, to)) =>
+          val (b, encClauses) = encodeBlockers(relevantBlockers)
+          encClauses ++ unrollInvariant(b, matcher.encoded, to)
+        case _ => Seq.empty
+      }
+
+      qClauses ++ mClauses
     }
   }