diff --git a/src/main/scala/leon/solvers/templates/QuantificationManager.scala b/src/main/scala/leon/solvers/templates/QuantificationManager.scala
index 58136e7e5b46fb0d569a9dbc3a4cd1482c7cb1f9..1bd5e3b51805f7735a97543272e8ee3642a7b450 100644
--- a/src/main/scala/leon/solvers/templates/QuantificationManager.scala
+++ b/src/main/scala/leon/solvers/templates/QuantificationManager.scala
@@ -10,8 +10,362 @@ import purescala.Types._
 
 import Instantiation._
 
+import scala.collection.mutable.{Map => MutableMap, Set => MutableSet}
+
+class QuantificationTemplate[T](
+  val quantificationManager: QuantificationManager[T],
+  val start: T,
+  val qs: (Identifier, T),
+  val holdVar: T,
+  val guardVar: T,
+  val quantifiers: Seq[(Identifier, T)],
+  val condVars: Map[Identifier, T],
+  val exprVars: Map[Identifier, T],
+  val clauses: Seq[T],
+  val blockers: Map[T, Set[TemplateCallInfo[T]]],
+  val applications: Map[T, Set[App[T]]],
+  val lambdas: Map[T, LambdaTemplate[T]]) {
+
+  def instantiate(blocker: T): Instantiation[T] = {
+    quantificationManager.instantiateQuantification(blocker, this)
+  }
+}
+
+object QuantificationTemplate {
+  def apply[T](
+    encoder: TemplateEncoder[T],
+    quantificationManager: QuantificationManager[T],
+    pathVar: (Identifier, T),
+    qs: (Identifier, T),
+    holder: Identifier,
+    guard: Identifier,
+    quantifiers: Seq[(Identifier, T)],
+    condVars: Map[Identifier, T],
+    exprVars: Map[Identifier, T],
+    guardedExprs: Map[Identifier, Seq[Expr]],
+    lambdas: Map[T, LambdaTemplate[T]],
+    subst: Map[Identifier, T]
+  ): QuantificationTemplate[T] = {
+
+    val holders: (Identifier, T) = holder -> encoder.encodeId(holder)
+    val guards: (Identifier, T) = guard -> encoder.encodeId(guard)
+
+    val (clauses, blockers, applications, _) =
+      Template.encode(encoder, pathVar, quantifiers, condVars, exprVars, guardedExprs, lambdas,
+        substMap = subst + holders + guards)
+
+    new QuantificationTemplate[T](quantificationManager,
+      pathVar._2, qs, holders._2, guards._2, quantifiers,
+      condVars, exprVars, clauses, blockers, applications, lambdas)
+  }
+}
+
 trait QuantificationManager[T] { self : LambdaManager[T] =>
 
+  private val stdQuantifiers: MutableMap[TypeTree, Seq[T]] = MutableMap.empty
+  private val quantified: MutableSet[T] = MutableSet.empty
+
+  private def standardQuantifiers(tpe: TypeTree, count: Int): Seq[T] = {
+    val quantifiers = stdQuantifiers.getOrElse(tpe, Seq.empty)
+    val currentCount = quantifiers.size
+
+    if (currentCount >= count) quantifiers.take(count) else {
+      val newQuantifiers = List.range(0, currentCount - count).map(_ => encoder.encodeId(FreshIdentifier("x", tpe)))
+      quantified ++= newQuantifiers
+
+      val allQuantifiers = quantifiers ++ newQuantifiers
+      stdQuantifiers(tpe) = allQuantifiers
+      allQuantifiers
+    }
+  }
+
+  private def freshQuantifierSubst: Map[T, T] = stdQuantifiers.flatMap { case (tpe, ids) =>
+    ids zip List.range(0, ids.size).map(_ => encoder.encodeId(FreshIdentifier("x", tpe)))
+  }.toMap
+
+  private val nextHolder: () => T = {
+    val id: Identifier = FreshIdentifier("ph", BooleanType)
+    () => encoder.encodeId(id)
+  }
+
+  private type Bindings = Set[(Option[T], FunctionType, Int, T)]
+  private var bindingsStack: List[Bindings] = List(Set.empty)
+  private def bindings: Bindings = bindingsStack.head
+  private def bindings_=(bs: Bindings): Unit = {
+    bindingsStack = bs :: bindingsStack.tail
+  }
+
+  private var quantificationsStack: List[Seq[Quantification]] = List(Seq.empty)
+  private def quantifications: Seq[Quantification] = quantificationsStack.head
+  private def quantifications_=(qs: Seq[Quantification]): Unit = {
+    quantificationsStack = qs :: quantificationsStack.tail
+  }
+
+  private var instantiatedAppsStack: List[Seq[(T, App[T], Map[T,T])]] = List(Seq.empty)
+  private def instantiatedApps: Seq[(T, App[T], Map[T,T])] = instantiatedAppsStack.head
+  private def instantiatedApps_=(ias: Seq[(T, App[T], Map[T,T])]): Unit = {
+    instantiatedAppsStack = ias :: instantiatedAppsStack.tail
+  }
+
+  private def known(tpe: FunctionType, idT: T): Boolean = freeLambdas(tpe)(idT) || byID.isDefinedAt(idT)
+
+  private class Quantification (
+    var holdVar: T,
+    val guardVar: T,
+    val condVars: Map[Identifier, T],
+    val exprVars: Map[Identifier, T],
+    val clauses: Seq[T],
+    val blockers: Map[T, Set[TemplateCallInfo[T]]],
+    val applications: Map[T, Set[App[T]]],
+    val lambdas: Map[T, LambdaTemplate[T]],
+    val binders: Set[App[T]]) {
+
+    def substitute(subst: Map[T, T]) = {
+      val substituter = encoder.substitute(subst)
+
+      new Quantification (
+        holdVar, guardVar, condVars, exprVars,
+        clauses map substituter,
+        blockers map { case (b, fis) =>
+          substituter(b) -> fis.map(fi => fi.copy(args = fi.args.map(substituter)))
+        },
+        applications map { case (b, fas) =>
+          substituter(b) -> fas.map(fa => fa.copy(caller = substituter(fa.caller), args = fa.args.map(substituter)))
+        },
+        lambdas map { case (idT, template) => substituter(idT) -> template.substitute(subst) },
+        binders map { case app @ App(caller, _, args) =>
+          app.copy(caller = substituter(caller), args = args.map(substituter))
+        }
+      )
+    }
+
+    def instantiate(blocker: T, app: App[T], quantifierSubst: Map[T, T]): Instantiation[T] = {
+      val App(caller, tpe, args) = app
+
+      // Build a mapping from applications in the quantified statement to all potential concrete
+      // applications previously encountered. Also make sure the current `app` is in the mapping
+      // as other instantiations have been performed previously when the associated applications
+      // were first encountered.
+      val appMappings: List[List[(T, App[T], App[T])]] = binders.toList
+        // 1. select an application in the quantified proposition for which the current app can
+        //    be bound when generating the new constraints
+        .filter(qapp => qapp.caller == caller || (qapp.tpe == tpe && !known(qapp.tpe, qapp.caller)))
+        // 2. build the instantiation mapping associated to the chosen current application binding
+        .flatMap { bindingApp => binders
+          // 2.1. select all potential matches for each quantified application
+          .map { case qapp @ App(qcaller, qtpe, qargs) =>
+            if (qapp == bindingApp) {
+              bindingApp -> Set(blocker -> app)
+            } else {
+              val instances = self.applications(qtpe).filter {
+                case (b, app @ App(caller, _, _)) => qcaller == caller || !known(qtpe, caller)
+              }
+
+              // concrete applications can appear multiple times in the constraint, and this is also the case
+              // for the current application for which we are generating the constraints
+              val withApp = if (qcaller == caller || !known(tpe, caller)) instances + (blocker -> app) else instances
+
+              // add quantified application to instances for constraints that depend on free variables
+              // this also make sure that constraints that don't depend on all variables will also be instantiated
+              // Note: we can use `blocker` here as the blocker since it is guaranteed true in this branch
+              val withAll = withApp + (blocker -> qapp)
+
+              qapp -> withAll
+            }
+          }
+          // 2.2. based on the possible bindings for each quantified application, build a set of
+          //      instantiation mappings that can be used to instantiate all necessary constraints
+          .foldLeft[List[List[(T, App[T], App[T])]]] (List(Nil)) {
+            case (mappings, (qapp, instances)) => instances.toList.flatMap {
+              case (b, app) => mappings.map(mapping => mapping :+ (b, app, qapp))
+            }
+          }
+        }
+
+      var instantiation = Instantiation.empty[T]
+
+      for (mapping <- appMappings) {
+        var constraints: List[T] = Nil
+        var subst: Map[T, T] = quantifierSubst
+
+        for {
+          (b, App(qcaller, _, qargs), App(caller, _, args)) <- mapping
+          _ = constraints :+= b
+          _ = if (qcaller != caller) constraints :+= encoder.mkEquals(qcaller, caller)
+          (qarg, arg) <- (qargs zip args)
+        } if (subst.isDefinedAt(qarg) || !quantified(qarg)) {
+          constraints :+= encoder.mkEquals(qarg, arg)
+        } else {
+          subst += qarg -> arg
+        }
+
+        val enabler = if (constraints.size == 1) constraints.head else encoder.mkAnd(constraints : _*)
+        val holder = nextHolder()
+
+        val lambdaSubstMap = lambdas.map { case (idT, lambda) => idT -> encoder.encodeId(lambda.id) }
+        val substMap = subst ++ lambdaSubstMap + (guardVar -> enabler) + (holdVar -> holder)
+        val substituter = encoder.substitute(subst)
+
+        val newClauses = enabler +: clauses.map(substituter)
+        val newBlockers = blockers.map { case (b, fis) =>
+          substituter(b) -> fis.map(fi => fi.copy(args = fi.args.map(substituter)))
+        }
+
+        val newApplications = applications.map { case (b, fas) =>
+          substituter(b) -> fas.map(fa => fa.copy(caller = substituter(fa.caller), args = fa.args.map(substituter)))
+        }
+
+        instantiation ++= (newClauses, newBlockers, Map.empty)
+
+        for ((idT, lambda) <- lambdas) {
+          val newIdT = substituter(idT)
+          val newTemplate = lambda.substitute(substMap)
+          instantiation ++= self.instantiateLambda(newIdT, newTemplate)
+        }
+
+        for ((b, apps) <- newApplications; app <- apps) {
+          instantiation ++= self.instantiateApp(b, app)
+        }
+
+        holdVar = holder
+      }
+
+      instantiation
+    }
+  }
+
+  def instantiateQuantification(blocker: T, template: QuantificationTemplate[T]): Instantiation[T] = {
+
+    val quantification: Quantification = {
+      val quantified = template.quantifiers.map(_._2).toSet
+
+      val bindingApps: Set[App[T]] = {
+        def rec(templates: Map[T, LambdaTemplate[T]]): Set[App[T]] = templates.flatMap {
+          case (_, template) => template.applications.flatMap(_._2).toSet ++ rec(template.lambdas)
+        }.toSet
+
+        val allApps = template.applications.flatMap(_._2).toSet ++ rec(template.lambdas)
+        for (app @ App(caller, tpe, args) <- allApps if args exists quantified) yield app
+      }
+
+      val q = new Quantification(
+        template.holdVar,
+        template.guardVar,
+        template.condVars,
+        template.exprVars,
+        template.clauses,
+        template.blockers,
+        template.applications,
+        template.lambdas,
+        bindingApps
+      )
+
+      val tpeCounts   = template.quantifiers.groupBy(_._1.getType).mapValues(_.map(_._2).toSeq)
+      val substMap    = tpeCounts.flatMap { case (tpe, idTs) => idTs zip standardQuantifiers(tpe, idTs.size) }.toMap
+      q.substitute(substMap + (template.start -> blocker))
+    }
+
+    val quantifierSubst: Map[T,T] = freshQuantifierSubst
+
+    var instantiation: Instantiation[T] = (quantification.clauses, quantification.blockers, Map.empty)
+    for (q <- quantifications; (b, apps) <- quantification.applications; app <- apps) {
+      instantiation ++= q.instantiate(b, app, quantifierSubst)
+    }
+
+    val qBindings: Bindings = quantification.binders.flatMap {
+      case App(caller, tpe, args) => args.zipWithIndex.collect {
+        case (qid, idx) if quantified(qid) =>
+          (if (known(tpe, caller)) Some(caller) else None, tpe, idx, qid)
+      }
+    }
+
+    val (callerBindings, typeBindings) = (bindings ++ qBindings).partition(_._1.isDefined)
+
+    val callerMap: Map[(T, Int), Set[T]] = callerBindings.groupBy(p => (p._1.get, p._3)).mapValues(_.map(_._4))
+    val typeMap: Map[(FunctionType, Int), Set[T]] = typeBindings.groupBy(p => (p._2, p._3)).mapValues(_.map(_._4))
+
+    val pairs: Set[(T, T)] = qBindings.flatMap { case (optIdT, tpe, idx, q) =>
+      val matches = typeMap(tpe -> idx) ++ optIdT.toSeq.flatMap(idT => callerMap(idT -> idx))
+      matches.map(q2 => q -> q2)
+    }
+
+    val mappings: List[Map[T, T]] =
+      pairs.groupBy(_._1).toSeq.foldLeft(List(Map.empty[T, T])) {
+        case (mappings, (_, pairs)) => pairs.toList.flatMap(p => mappings.map(mapping => mapping + p))
+      }
+
+    val newQuantifications = for (mapping <- mappings) yield {
+      val ph = nextHolder()
+
+      val freshConds = quantification.condVars.map(p => p._1.freshen -> p._2)
+      val freshExprs = quantification.exprVars.map(p => p._1.freshen -> p._2)
+
+      val substMap: Map[T, T] = mapping ++
+        (freshConds ++ freshExprs).map { case (id, idT) => idT -> encoder.encodeId(id) } ++
+        quantification.lambdas.map { case (idT, template) => idT -> encoder.encodeId(template.id) }
+
+      val substituter = encoder.substitute(substMap)
+
+      new Quantification(ph, quantification.guardVar,
+        freshConds mapValues substituter,
+        freshExprs mapValues substituter,
+        quantification.clauses map substituter,
+        quantification.blockers map { case (b, fis) =>
+          substituter(b) -> fis.map(fi => fi.copy(args = fi.args.map(substituter)))
+        },
+        quantification.applications map { case (b, fas) =>
+          substituter(b) -> fas.map(fa => fa.copy(caller = substituter(fa.caller), args = fa.args.map(substituter)))
+        },
+        quantification.lambdas map { case (idT, template) => substituter(idT) -> template.substitute(mapping) },
+        quantification.binders map { case app @ App(caller, _, args) =>
+          app.copy(caller = substituter(caller), args = args.map(substituter))
+        }
+      )
+    }
+
+    val eqClause = {
+      val holders = newQuantifications.map(_.holdVar)
+      val newHolders = if (holders.size > 1) encoder.mkAnd(holders : _*) else holders.head
+      encoder.mkEquals(template.qs._2, newHolders)
+    }
+
+    instantiation = (instantiation._1 :+ eqClause, instantiation._2, instantiation._3)
+
+    instantiatedApps = for ((b, app, qSubst) <- instantiatedApps) yield {
+      val nqSubst = if (qSubst.size == stdQuantifiers.map(_._2.size).sum) qSubst else {
+        stdQuantifiers.flatMap { case (tpe, ids) =>
+          val recent = ids.dropWhile(qSubst.isDefinedAt)
+          recent zip recent.map(_ => encoder.encodeId(FreshIdentifier("x", tpe)))
+        }.toMap
+      }
+
+      for (q <- newQuantifications) {
+        instantiation ++= q.instantiate(b, app, nqSubst)
+      }
+
+      (b, app, nqSubst)
+    }
+
+    for ((b, apps) <- quantification.applications; app <- apps) {
+      instantiatedApps :+= (b, app, quantifierSubst)
+    }
+
+    instantiation
+  }
+
+  override def instantiateApp(blocker: T, app: App[T]): Instantiation[T] = {
+    val quantifierSubst: Map[T, T] = freshQuantifierSubst
+
+    var instantiation = Instantiation.empty[T]
+    for (q <- quantifications) {
+      instantiation ++= q.instantiate(blocker, app, quantifierSubst)
+    }
+
+    instantiatedApps :+= (blocker, app, quantifierSubst)
+    instantiation
+  }
+
+  /*
   private class QuantificationScope(
     val quantifiedApps: List[App[T]],
     val quantifiers: Map[Identifier, T],
@@ -70,7 +424,7 @@ trait QuantificationManager[T] { self : LambdaManager[T] =>
 
     val quantifiers: Seq[(Identifier, T)] = quantifierVars.map(id => id -> encoder.encodeId(id))
     val quantified: Set[T] = quantifiers.map(_._2).toSet
-    val pathVar = startVar -> encoder.encodeId(startVar)
+    val pathVar = startVar -> subst(startVar)
     val (clauses, blockers, apps, _) = Template.encode(encoder, pathVar, quantifiers, condVars, exprVars, guardedExprs, lambdas, subst)
 
     val bindingApps: Set[App[T]] = {
@@ -125,11 +479,13 @@ trait QuantificationManager[T] { self : LambdaManager[T] =>
         case (mappings, (_, pairs)) => pairs.toList.flatMap(p => mappings.map(mapping => mapping + p))
       }
 
-    val (allClauses, allBlockers, allApps) = {
+    val (allClauses, allBlockers, allApps, quantifiedApps) = {
       var allClauses  : Seq[T]                           = Seq.empty
       var allBlockers : Map[T, Set[TemplateCallInfo[T]]] = Map.empty.withDefaultValue(Set.empty)
       var allApps     : Map[T, Set[App[T]]]              = Map.empty.withDefaultValue(Set.empty)
 
+      var quantifiedApps : Set[App[T]] = Set.empty
+
       for (mapping <- mappings) {
         val substituter = encoder.substitute(mapping)
         allClauses ++= clauses.map(substituter)
@@ -145,17 +501,15 @@ trait QuantificationManager[T] { self : LambdaManager[T] =>
           val fasp = fas.map(fa => fa.copy(caller = substituter(fa.caller), args = fa.args.map(substituter)))
           allApps += bp -> (allApps(bp) ++ fasp)
         }
+
+        quantifiedApps ++= bindingApps.map { case app @ App(caller, _, args) =>
+          app.copy(caller = substituter(caller), args = args.map(substituter))
+        }
       }
 
-      (allClauses, allBlockers, allApps)
+      (allClauses, allBlockers, allApps, quantifiedApps)
     }
 
-    val quantifiedApps: Set[(T, App[T])] = for {
-      (b, bApps) <- allApps.toSet
-      app @ App(caller, tpe, args) <- bApps
-      if args exists quantified
-    } yield (b, app)
-
     scopes = new QuantificationScope(
       currentScope.quantifiedApps ++ quantifiedApps,
       currentScope.quantifiers ++ quantifiers,
@@ -233,14 +587,15 @@ trait QuantificationManager[T] { self : LambdaManager[T] =>
         case (id, idT) if !subst.isDefinedAt(idT) => idT -> encoder.encodeId(id)
       }
 
-      val bp = encoder.encodeId(startId)
+      val bp = encoder.encodeId(FreshIdentifier("qb", BooleanType))
+      // TODO: empty `constraints`
       val enabler = encoder.mkEquals(bp, encoder.mkAnd(constraints : _*))
 
       val lambdaSubstMap = lambdas.map { case (idT, lambda) => idT -> encoder.encodeId(lambda.id) }
       val substMap = subst ++ lambdaSubstMap + (start -> enabler)
       val substituter = encoder.substitute(subst)
 
-      val newClauses = clauses.map(substituter)
+      val newClauses = enabler +: clauses.map(substituter)
       val newBlockers = blockers.map { case (b, fis) =>
         substituter(b) -> fis.map(fi => fi.copy(args = fi.args.map(substituter)))
       }
@@ -264,4 +619,5 @@ trait QuantificationManager[T] { self : LambdaManager[T] =>
 
     instantiation
   }
+  */
 }
diff --git a/src/main/scala/leon/solvers/templates/TemplateGenerator.scala b/src/main/scala/leon/solvers/templates/TemplateGenerator.scala
index 1eac5171272810efc23750e3745a7b03ce5fbf46..ef2ca6e91855e80f34e520158859d93bfeed7fe5 100644
--- a/src/main/scala/leon/solvers/templates/TemplateGenerator.scala
+++ b/src/main/scala/leon/solvers/templates/TemplateGenerator.scala
@@ -72,16 +72,16 @@ class TemplateGenerator[T](val encoder: TemplateEncoder[T],
 
     val substMap : Map[Identifier, T] = arguments.toMap + pathVar
 
-    val (bodyConds, bodyExprs, bodyGuarded, bodyLambdas) = if (isRealFunDef) {
+    val (bodyConds, bodyExprs, bodyGuarded, bodyLambdas, bodyQuantifications) = if (isRealFunDef) {
       invocationEqualsBody.map(expr => mkClauses(start, expr, substMap)).getOrElse {
-        (Map[Identifier,T](), Map[Identifier,T](), Map[Identifier,Seq[Expr]](), Map[T,LambdaTemplate[T]]())
+        (Map[Identifier,T](), Map[Identifier,T](), Map[Identifier,Seq[Expr]](), Map[T,LambdaTemplate[T]](), Seq[QuantificationTemplate[T]]())
       }
     } else {
       mkClauses(start, lambdaBody.get, substMap)
     }
 
     // Now the postcondition.
-    val (condVars, exprVars, guardedExprs, lambdas) = tfd.postcondition match {
+    val (condVars, exprVars, guardedExprs, lambdas, quantifications) = tfd.postcondition match {
       case Some(post) =>
         val newPost : Expr = application(matchToIfThenElse(post), Seq(invocation))
 
@@ -96,19 +96,19 @@ class TemplateGenerator[T](val encoder: TemplateEncoder[T],
             newPost
           }
 
-        val (postConds, postExprs, postGuarded, postLambdas) = mkClauses(start, postHolds, substMap)
+        val (postConds, postExprs, postGuarded, postLambdas, postQuantifications) = mkClauses(start, postHolds, substMap)
         val allGuarded = (bodyGuarded.keys ++ postGuarded.keys).map { k => 
           k -> (bodyGuarded.getOrElse(k, Seq.empty) ++ postGuarded.getOrElse(k, Seq.empty))
         }.toMap
 
-        (bodyConds ++ postConds, bodyExprs ++ postExprs, allGuarded, bodyLambdas ++ postLambdas)
+        (bodyConds ++ postConds, bodyExprs ++ postExprs, allGuarded, bodyLambdas ++ postLambdas, bodyQuantifications ++ postQuantifications)
 
       case None =>
-        (bodyConds, bodyExprs, bodyGuarded, bodyLambdas)
+        (bodyConds, bodyExprs, bodyGuarded, bodyLambdas, bodyQuantifications)
     }
 
     val template = FunctionTemplate(tfd, encoder, lambdaManager,
-      pathVar, arguments, condVars, exprVars, guardedExprs, lambdas, isRealFunDef)
+      pathVar, arguments, condVars, exprVars, guardedExprs, quantifications, lambdas, isRealFunDef)
     cache += tfd -> template
     template
   }
@@ -125,7 +125,7 @@ class TemplateGenerator[T](val encoder: TemplateEncoder[T],
   }
 
   def mkClauses(pathVar: Identifier, expr: Expr, substMap: Map[Identifier, T]):
-               (Map[Identifier,T], Map[Identifier,T], Map[Identifier, Seq[Expr]], Map[T, LambdaTemplate[T]]) = {
+               (Map[Identifier,T], Map[Identifier,T], Map[Identifier, Seq[Expr]], Map[T, LambdaTemplate[T]], Seq[QuantificationTemplate[T]]) = {
 
     var condVars = Map[Identifier, T]()
     @inline def storeCond(id: Identifier) : Unit = condVars += id -> encoder.encodeId(id)
@@ -152,6 +152,10 @@ class TemplateGenerator[T](val encoder: TemplateEncoder[T],
       idT
     }
 
+    var quantifications = Seq[QuantificationTemplate[T]]()
+    @inline def registerQuantification(quantification: QuantificationTemplate[T]): Unit =
+      quantifications :+= quantification
+
     var lambdas = Map[T, LambdaTemplate[T]]()
     @inline def registerLambda(idT: T, lambda: LambdaTemplate[T]) : Unit = lambdas += idT -> lambda
 
@@ -263,26 +267,49 @@ class TemplateGenerator[T](val encoder: TemplateEncoder[T],
           val lid = FreshIdentifier("lambda", l.getType, true)
           val clause = appliedEquals(Variable(lid), l)
 
-          val localSubst : Map[Identifier, T] = substMap ++ condVars ++ exprVars ++ lambdaVars
-          val clauseSubst : Map[Identifier, T] = localSubst ++ (idArgs zip trArgs)
-          val (lambdaConds, lambdaExprs, lambdaGuarded, lambdaTemplates) = mkClauses(pathVar, clause, clauseSubst)
+          val localSubst: Map[Identifier, T] = substMap ++ condVars ++ exprVars ++ lambdaVars
+          val clauseSubst: Map[Identifier, T] = localSubst ++ (idArgs zip trArgs)
+          val (lambdaConds, lambdaExprs, lambdaGuarded, lambdaTemplates, lambdaQuants) = mkClauses(pathVar, clause, clauseSubst)
+          assert(lambdaQuants.isEmpty, "Unhandled quantification in lambdas in " + clause)
 
           val ids: (Identifier, T) = lid -> storeLambda(lid)
           val dependencies: Map[Identifier, T] = variablesOf(l).map(id => id -> localSubst(id)).toMap
-          val template = LambdaTemplate(ids, encoder, lambdaManager, pathVar -> encodedCond(pathVar), idArgs zip trArgs, lambdaConds, lambdaExprs, lambdaGuarded, lambdaTemplates, localSubst, dependencies, l)
+          val template = LambdaTemplate(ids, encoder, lambdaManager, pathVar -> encodedCond(pathVar),
+            idArgs zip trArgs, lambdaConds, lambdaExprs, lambdaGuarded, lambdaTemplates, localSubst, dependencies, l)
           registerLambda(ids._2, template)
 
           Variable(lid)
 
-        case Operator(as, r) => r(as.map(a => rec(pathVar, a)))
+        case f @ Forall(args, body) =>
+          val idQuantifiers : Seq[Identifier] = args.map(_.id)
+          val trQuantifiers : Seq[T] = idQuantifiers.map(encoder.encodeId)
+
+          val q: Identifier = FreshIdentifier("q", BooleanType)
+          val ph: Identifier = FreshIdentifier("ph", BooleanType)
+          val guard: Identifier = FreshIdentifier("guard", BooleanType)
+
+          val clause = Equals(Variable(q), And(Variable(ph), Implies(Variable(guard), body)))
 
+          val qs: (Identifier, T) = q -> encoder.encodeId(q)
+          val localSubst: Map[Identifier, T] = substMap ++ condVars ++ exprVars ++ lambdaVars
+          val clauseSubst: Map[Identifier, T] = localSubst ++ (idQuantifiers zip trQuantifiers)
+          val (qConds, qExprs, qGuarded, qTemplates, qQuants) = mkClauses(pathVar, clause, clauseSubst)
+          assert(qQuants.isEmpty, "Unhandled nested quantification in "+clause)
+
+          val template = QuantificationTemplate[T](encoder, lambdaManager, pathVar -> encodedCond(pathVar),
+            qs, ph, guard, idQuantifiers zip trQuantifiers, qConds, qExprs, qGuarded, qTemplates, localSubst)
+          registerQuantification(template)
+
+          Variable(q)
+
+        case Operator(as, r) => r(as.map(a => rec(pathVar, a)))
       }
     }
 
     val p = rec(pathVar, expr)
     storeGuarded(pathVar, p)
 
-    (condVars, exprVars, guardedExprs, lambdas)
+    (condVars, exprVars, guardedExprs, lambdas, quantifications)
   }
 
 }
diff --git a/src/main/scala/leon/solvers/templates/Templates.scala b/src/main/scala/leon/solvers/templates/Templates.scala
index f19357a1ce4c174c1c2a42bcf13019c49933b301..cd0fe0e07e3eed85e96bca0df4196ab0ff054f7e 100644
--- a/src/main/scala/leon/solvers/templates/Templates.scala
+++ b/src/main/scala/leon/solvers/templates/Templates.scala
@@ -54,6 +54,7 @@ trait Template[T] { self =>
   val clauses : Seq[T]
   val blockers : Map[T, Set[TemplateCallInfo[T]]]
   val applications : Map[T, Set[App[T]]]
+  val quantifications: Seq[QuantificationTemplate[T]]
   val lambdas : Map[T, LambdaTemplate[T]]
 
   private var substCache : Map[Seq[T],Map[T,T]] = Map.empty
@@ -232,6 +233,7 @@ object FunctionTemplate {
     condVars: Map[Identifier, T],
     exprVars: Map[Identifier, T],
     guardedExprs: Map[Identifier, Seq[Expr]],
+    quantifications: Seq[QuantificationTemplate[T]],
     lambdas: Map[T, LambdaTemplate[T]],
     isRealFunDef: Boolean
   ) : FunctionTemplate[T] = {
@@ -257,6 +259,7 @@ object FunctionTemplate {
       clauses,
       blockers,
       applications,
+      quantifications,
       lambdas,
       isRealFunDef,
       funString
@@ -275,6 +278,7 @@ class FunctionTemplate[T] private(
   val clauses: Seq[T],
   val blockers: Map[T, Set[TemplateCallInfo[T]]],
   val applications: Map[T, Set[App[T]]],
+  val quantifications: Seq[QuantificationTemplate[T]],
   val lambdas: Map[T, LambdaTemplate[T]],
   isRealFunDef: Boolean,
   stringRepr: () => String) extends Template[T] {
@@ -393,6 +397,9 @@ class LambdaTemplate[T] private (
   private[templates] val structuralKey: Lambda,
   stringRepr: () => String) extends Template[T] {
 
+  // Universal quantification is not allowed inside closure bodies!
+  val quantifications: Seq[QuantificationTemplate[T]] = Seq.empty
+
   val tpe = id.getType.asInstanceOf[FunctionType]
 
   def substitute(substMap: Map[T,T]): LambdaTemplate[T] = {