diff --git a/src/main/php/lang/ast/emit/Declaration.class.php b/src/main/php/lang/ast/emit/Declaration.class.php
index f3d58a3a..b79aac95 100755
--- a/src/main/php/lang/ast/emit/Declaration.class.php
+++ b/src/main/php/lang/ast/emit/Declaration.class.php
@@ -1,6 +1,6 @@
 <?php namespace lang\ast\emit;
 
-use lang\ast\nodes\{EnumCase, Property};
+use lang\ast\nodes\{EnumCase, Property, Method};
 
 class Declaration extends Type {
   private $type, $result;
@@ -19,6 +19,24 @@ public function __construct($type, $result) {
   /** @return string */
   public function name() { return ltrim($this->type->name, '\\'); }
 
+  /**
+   * Returns the (fully qualified) default implementations' trait name for
+   * interfaces, or `null`.
+   *
+   * @return ?string
+   */
+  public function defaultImplementations() {
+    if ('interface' !== $this->type->kind) return null;
+
+    foreach ($this->type->body as $member) {
+      if ($member instanceof Method && null !== $member->body) {
+        $p= strrpos($this->type->name, '\\');
+        return substr($this->type->name, 0, $p).'\\__'.substr($this->type->name, $p + 1).'_Defaults';
+      }
+    }
+    return null;
+  }
+
   /**
    * Returns whether a given member is an enum case
    *
diff --git a/src/main/php/lang/ast/emit/InType.class.php b/src/main/php/lang/ast/emit/InType.class.php
index 4df91107..e356fa47 100755
--- a/src/main/php/lang/ast/emit/InType.class.php
+++ b/src/main/php/lang/ast/emit/InType.class.php
@@ -6,6 +6,7 @@ class InType {
   public $init= [];
   public $statics= [];
   public $virtual= [];
+  public $defaultImplementations= [];
 
   public function __construct($type) {
     $this->type= $type;
diff --git a/src/main/php/lang/ast/emit/Incomplete.class.php b/src/main/php/lang/ast/emit/Incomplete.class.php
index f4fcaffb..872b2da1 100755
--- a/src/main/php/lang/ast/emit/Incomplete.class.php
+++ b/src/main/php/lang/ast/emit/Incomplete.class.php
@@ -18,4 +18,14 @@ public function name() { return $this->name; }
   public function rewriteEnumCase($member) {
     return false;
   }
+
+  /**
+   * Returns the (fully qualified) default implementations' trait name for
+   * interfaces, or `null`.
+   *
+   * @return ?string
+   */
+  public function defaultImplementations() {
+    return null;
+  }
 }
\ No newline at end of file
diff --git a/src/main/php/lang/ast/emit/PHP.class.php b/src/main/php/lang/ast/emit/PHP.class.php
index 753a6a00..35bcfcac 100755
--- a/src/main/php/lang/ast/emit/PHP.class.php
+++ b/src/main/php/lang/ast/emit/PHP.class.php
@@ -13,9 +13,10 @@
   Property,
   ScopeExpression,
   UnpackExpression,
+  TraitDeclaration,
   Variable
 };
-use lang\ast\types\{IsUnion, IsFunction, IsArray, IsMap, IsNullable, IsExpression};
+use lang\ast\types\{IsUnion, IsFunction, IsArray, IsMap, IsNullable, IsValue, IsExpression};
 use lang\ast\{Emitter, Node, Type, Result};
 
 abstract class PHP extends Emitter {
@@ -424,10 +425,14 @@ protected function emitClass($result, $class) {
     $result->at($class->declared)->out->write(implode(' ', $class->modifiers).' class '.$class->declaration());
     $class->parent && $result->out->write(' extends '.$class->parent->literal());
 
+    $defaults= [];
     if ($class->implements) {
       $list= '';
       foreach ($class->implements as $type) {
         $list.= ', '.$type->literal();
+        if ($default= $result->lookup($type->literal())->defaultImplementations()) {
+          $defaults[]= $default;
+        }
       }
       $result->out->write(' implements '.substr($list, 2));
     }
@@ -473,6 +478,9 @@ protected function emitClass($result, $class) {
       $result->out->write('}');
     }
 
+    // Use interface default implementations
+    $defaults && $result->out->write('use '.implode(', ', $defaults).';');
+
     $result->out->write('static function __init() {');
     $this->emitInitializations($result, $context->statics);
     $this->emitMeta($result, $class->name, $class->annotations, $class->comment);
@@ -543,6 +551,14 @@ protected function emitInterface($result, $interface) {
     $result->out->write('}');
 
     $this->emitMeta($result, $interface->name, $interface->annotations, $interface->comment);
+
+    // Emit default implementations
+    if ($defaults= $result->codegen->scope[0]->defaultImplementations) {
+      $p= strrpos($interface->name, '\\');
+      $name= substr($interface->name, 0, $p).'\\__'.substr($interface->name, $p + 1).'_Defaults';
+      $this->emitOne($result, new TraitDeclaration([], new IsValue($name), $defaults));
+    }
+
     $result->codegen->leave();
   }
 
@@ -559,6 +575,7 @@ protected function emitTrait($result, $trait) {
     $result->out->write('}');
 
     $this->emitMeta($result, $trait->name, $trait->annotations, $trait->comment);
+
     $result->codegen->leave();
   }
 
@@ -653,6 +670,9 @@ protected function emitMethod($result, $method) {
 
     if (null === $method->body) {
       $result->out->write(';');
+    } else if ('interface' === $result->codegen->scope[0]->type->kind) {
+      $result->out->write(';');
+      $result->codegen->scope[0]->defaultImplementations[]= $method;
     } else {
       $result->out->write(' {');
 
diff --git a/src/main/php/lang/ast/emit/Reflection.class.php b/src/main/php/lang/ast/emit/Reflection.class.php
index 858439b4..a78e5b1d 100755
--- a/src/main/php/lang/ast/emit/Reflection.class.php
+++ b/src/main/php/lang/ast/emit/Reflection.class.php
@@ -23,6 +23,22 @@ public function __construct($type) {
   /** @return string */
   public function name() { return $this->reflect->name; }
 
+  /**
+   * Returns the (fully qualified) default implementations' trait name for
+   * interfaces, or `null`.
+   *
+   * @return ?string
+   */
+  public function defaultImplementations() {
+    if (!$this->reflect->isInterface()) return null;
+
+    $defaults= false === ($p= strrpos($this->reflect->name, '\\'))
+      ? "__{$this->reflect->name}_Defaults"
+      : substr($this->reflect->name, 0, $p).'\\__'.substr($this->reflect->name, $p + 1).'_Defaults'
+    ;
+    return trait_exists($defaults, false) ? '\\'.$defaults : null;
+  }
+
   /**
    * Returns whether a given member is an enum case
    *
diff --git a/src/test/php/lang/ast/unittest/emit/TypeDeclarationTest.class.php b/src/test/php/lang/ast/unittest/emit/TypeDeclarationTest.class.php
index 32401255..41f200a0 100755
--- a/src/test/php/lang/ast/unittest/emit/TypeDeclarationTest.class.php
+++ b/src/test/php/lang/ast/unittest/emit/TypeDeclarationTest.class.php
@@ -69,6 +69,22 @@ public function interface_type_with_method() {
     );
   }
 
+  #[Test, Values(['', 'namespace test;'])]
+  public function interface_type_with_default_method($namespace) {
+    $i= $this->type($namespace.' interface <T> {
+      public function all();
+      public function filter($filter) {
+        foreach ($this->all() as $element) {
+          $filter($element) || yield $element;
+        }
+      }
+    }');
+    $t= $this->type($namespace.' class <T> implements \\'.$i->literal().'{
+      public function all() { return [1, 2, 3]; }
+    }');
+    Assert::equals([2], iterator_to_array($t->newInstance()->filter(function($i) { return $i % 2; })));
+  }
+
   #[Test, Values(['public', 'private', 'protected']), Runtime(php: '>=7.1.0')]
   public function constant($modifiers) {
     $c= $this->declare('class %T { '.$modifiers.' const test = 1; }')->constant('test');
