diff --git a/src/main/scala/leon/codegen/CodeGenPhase.scala b/src/main/scala/leon/codegen/CodeGenPhase.scala
index bdc717c1d37aaf69b3979652016e44cb2dca2572..e2fb321c6dbf9251d0531a0d46c533e412a41bcd 100644
--- a/src/main/scala/leon/codegen/CodeGenPhase.scala
+++ b/src/main/scala/leon/codegen/CodeGenPhase.scala
@@ -15,15 +15,16 @@ object CodeGenPhase extends LeonPhase[Program,CompilationResult] {
   def run(ctx : LeonContext)(p : Program) : CompilationResult = {
     import CodeGeneration._
 
+    // This sets up an environment where all classes and all functions have names.
     implicit val env = CompilationEnvironment.fromProgram(p)
 
-    val cName = programToClassName(p)
-
-    for((p,cs) <- p.algebraicDataTypes) {
-      // val acf = new ClassFile(p....
+    for((parent,children) <- p.algebraicDataTypes) {
+      val acf = compileAbstractClassDef(p, parent)
+      val ccfs = children.map(c => compileCaseClassDef(p, c))
     } 
 
-    val cf = new ClassFile(cName, None)
+    val mainClassName = defToJVMName(p, p.mainObject)
+    val cf = new ClassFile(mainClassName, None)
     cf.addDefaultConstructor
 
     cf.setFlags((
@@ -51,7 +52,7 @@ object CodeGenPhase extends LeonPhase[Program,CompilationResult] {
       CodeGeneration.compileFunDef(funDef, m.codeHandler)
     }
 
-    cf.writeToFile(cName + ".class")
+    cf.writeToFile(mainClassName + ".class")
 
     CompilationResult(successful = true)
   } 
diff --git a/src/main/scala/leon/codegen/CodeGeneration.scala b/src/main/scala/leon/codegen/CodeGeneration.scala
index 47fe2062f74283a11d1e5b4825677a4275ae5498..2410b8025a248b23ede9758628ebc815f83c3045 100644
--- a/src/main/scala/leon/codegen/CodeGeneration.scala
+++ b/src/main/scala/leon/codegen/CodeGeneration.scala
@@ -7,15 +7,22 @@ import purescala.Trees._
 import purescala.TypeTrees._
 
 import cafebabe._
-import cafebabe.ByteCodes._
 import cafebabe.AbstractByteCodes._
+import cafebabe.ByteCodes._
+import cafebabe.ClassFileTypes._
+import cafebabe.Flags._
 
 object CodeGeneration {
-  def programToClassName(p : Program) : String = "Leon$CodeGen$" + p.mainObject.id.uniqueName
+  def defToJVMName(p : Program, d : Definition) : String = "Leon$CodeGen$" + d.id.uniqueName
 
   def typeToJVM(tpe : TypeTree)(implicit env : CompilationEnvironment) : String = tpe match {
     case Int32Type => "I"
+
     case BooleanType => "Z"
+
+    case c : ClassType =>
+      env.classDefToName(c.classDef).map(n => "L" + n + ";").getOrElse("Unsupported class " + c.id)
+
     case _ => throw CompilationException("Unsupported type : " + tpe)
   }
 
@@ -170,4 +177,68 @@ object CodeGeneration {
       throw CompilationException("Unknown variable : " + id)
     }
   }
+
+  def compileAbstractClassDef(p : Program, acd : AbstractClassDef)(implicit env : CompilationEnvironment) : ClassFile = {
+    val cName = defToJVMName(p, acd)
+
+    val cf  = new ClassFile(cName, None)
+    cf.setFlags((
+      CLASS_ACC_SUPER |
+      CLASS_ACC_PUBLIC |
+      CLASS_ACC_ABSTRACT
+    ).asInstanceOf[U2])
+
+    cf.addDefaultConstructor
+
+    //cf.writeToFile(cName + ".class")
+    cf
+  }
+
+  def compileCaseClassDef(p : Program, ccd : CaseClassDef)(implicit env : CompilationEnvironment) : ClassFile = {
+    assert(ccd.hasParent)
+
+    val cName = defToJVMName(p, ccd)
+    val pName = defToJVMName(p, ccd.parent.get)
+
+    val cf = new ClassFile(cName, Some(pName))
+    cf.setFlags((
+      CLASS_ACC_SUPER |
+      CLASS_ACC_PUBLIC |
+      CLASS_ACC_FINAL
+    ).asInstanceOf[U2])
+
+    if(ccd.fields.isEmpty) {
+      cf.addDefaultConstructor
+    } else {
+      val namesTypes = ccd.fields.map { vd => (vd.id.name, typeToJVM(vd.tpe)) }
+
+      for((nme, jvmt) <- namesTypes) {
+        val fh = cf.addField(jvmt, nme)
+        fh.setFlags((
+          FIELD_ACC_PUBLIC |
+          FIELD_ACC_FINAL
+        ).asInstanceOf[U2])
+      }
+
+      val cmh = cf.addConstructor(namesTypes.map(_._2).toList).codeHandler
+
+      cmh << ALoad(0) << InvokeSpecial(pName, cafebabe.Defaults.constructorName, "()V")
+
+      var c = 1
+      for((nme, jvmt) <- namesTypes) {
+        cmh << ALoad(0)
+        cmh << (jvmt match {
+          case "I" | "Z" => ILoad(c)
+          case _ => ALoad(c)
+        })
+        cmh << PutField(cName, nme, jvmt)
+        c += 1
+      }
+      cmh << RETURN
+      cmh.freeze
+    }
+
+    //cf.writeToFile(cName + ".class")
+    cf
+  }
 }
diff --git a/src/main/scala/leon/codegen/CompilationEnvironment.scala b/src/main/scala/leon/codegen/CompilationEnvironment.scala
index 2bec36229355f8f1c82ba171336df49314ea219c..355caea9138420d0c5306effb511b7098107f9e6 100644
--- a/src/main/scala/leon/codegen/CompilationEnvironment.scala
+++ b/src/main/scala/leon/codegen/CompilationEnvironment.scala
@@ -10,6 +10,8 @@ abstract class CompilationEnvironment() {
   //   - a mapping of function defs to class + method name
   //   - a mapping of class defs to class names
   //   - a mapping of class fields to fields
+  
+  def classDefToName(classDef : ClassTypeDef) : Option[String]
 
   def funDefToMethod(funDef : FunDef) : Option[(String,String,String)]
 
@@ -18,6 +20,7 @@ abstract class CompilationEnvironment() {
   /** Augment the environment with new local var. mappings. */
   def withVars(pairs : Map[Identifier,Int]) = {
     new CompilationEnvironment {
+      def classDefToName(classDef : ClassTypeDef) = self.classDefToName(classDef)
       def funDefToMethod(funDef : FunDef) = self.funDefToMethod(funDef)
       def varToLocal(v : Identifier) = pairs.get(v).orElse(self.varToLocal(v))
     }
@@ -25,20 +28,21 @@ abstract class CompilationEnvironment() {
 }
 
 object CompilationEnvironment {
-
-  lazy val empty = new CompilationEnvironment {
-    def funDefToMethod(funDef : FunDef) = None
-    def varToLocal(v : Identifier) = None
-  }
-
   def fromProgram(p : Program) : CompilationEnvironment = {
     import CodeGeneration.typeToJVM
 
     // This should change: it should contain the case classes before
     // we go and generate function signatures.
-    implicit val env = empty
+    implicit val initial = new CompilationEnvironment {
+      private val cNames : Map[ClassTypeDef,String] = 
+        p.definedClasses.map(c => (c, CodeGeneration.defToJVMName(p, c))).toMap 
 
-    val className = CodeGeneration.programToClassName(p)
+      def classDefToName(classDef : ClassTypeDef) = cNames.get(classDef)
+      def funDefToMethod(funDef : FunDef) = None
+      def varToLocal(v : Identifier) = None
+    }
+
+    val className = CodeGeneration.defToJVMName(p, p.mainObject)
 
     val fs = p.definedFunctions.filter(_.hasImplementation)
 
@@ -49,8 +53,8 @@ object CompilationEnvironment {
     }).toMap
 
     new CompilationEnvironment {
+      def classDefToName(classDef : ClassTypeDef) = initial.classDefToName(classDef)
       def funDefToMethod(funDef : FunDef) = fMap.get(funDef)
-
       def varToLocal(v : Identifier) = None
     }
   }
diff --git a/unmanaged/32/cafebabe_2.9.2-1.2.jar b/unmanaged/32/cafebabe_2.9.2-1.2.jar
index ccfc6ff432dfbae28dbb6508948a4a87dc52524f..66e18c2577b7570e01e67c4f8cdb94eafd934682 100644
Binary files a/unmanaged/32/cafebabe_2.9.2-1.2.jar and b/unmanaged/32/cafebabe_2.9.2-1.2.jar differ