diff --git a/src/app/Fs/Item.php b/src/app/Fs/Item.php
index 6d1438e3..edde2ff3 100644
--- a/src/app/Fs/Item.php
+++ b/src/app/Fs/Item.php
@@ -1,178 +1,170 @@
 <?php
 
 namespace App\Fs;
 
 use App\User;
+use App\Traits\BelongsToUserTrait;
 use App\Traits\UuidStrKeyTrait;
 use Illuminate\Database\Eloquent\Casts\Attribute;
 use Illuminate\Database\Eloquent\Model;
 use Illuminate\Database\Eloquent\SoftDeletes;
 
 /**
  * The eloquent definition of a filesystem item.
  *
  * @property string $id        Item identifier
  * @property int    $type      Item type
  * @property string $path      Item path (readonly)
  * @property int    $user_id   Item owner
  */
 class Item extends Model
 {
+    use BelongsToUserTrait;
     use SoftDeletes;
     use UuidStrKeyTrait;
 
     public const TYPE_FILE       = 1;
     public const TYPE_FOLDER     = 2;
     public const TYPE_INCOMPLETE = 4;
 
     /** @var array<int, string> The attributes that are mass assignable */
     protected $fillable = ['user_id', 'type'];
 
     /** @var array<string, string> The attributes that should be cast */
     protected $casts = [
         'created_at' => 'datetime:Y-m-d H:i:s',
         'updated_at' => 'datetime:Y-m-d H:i:s',
     ];
 
     /** @var string Database table name */
     protected $table = 'fs_items';
 
 
     /**
      * COntent chunks of this item (file).
      *
      * @return \Illuminate\Database\Eloquent\Relations\HasMany
      */
     public function chunks()
     {
         return $this->hasMany(Chunk::class);
     }
 
     /**
      * Getter for the file path (without the filename) in the storage.
      *
      * @return \Illuminate\Database\Eloquent\Casts\Attribute
      */
     protected function path(): Attribute
     {
         return Attribute::make(
             get: function ($value) {
                 if (empty($this->id)) {
                     throw new \Exception("Cannot get path for an item without ID");
                 }
 
                 $id = substr($this->id, 0, 6);
 
                 return implode('/', str_split($id, 2));
             }
         );
     }
 
     /**
      * Any (additional) properties of this item.
      *
      * @return \Illuminate\Database\Eloquent\Relations\HasMany
      */
     public function properties()
     {
         return $this->hasMany(Property::class);
     }
 
     /**
      * Obtain the value for an item property
      *
      * @param string $key     Property name
      * @param mixed  $default Default value, to be used if not found
      *
      * @return string|null Property value
      */
     public function getProperty(string $key, $default = null)
     {
         $attr = $this->properties()->where('key', $key)->first();
 
         return $attr ? $attr->value : $default;
     }
 
     /**
      * Obtain the values for many properties in one go (for better performance).
      *
      * @param array $keys Property names
      *
      * @return array Property key=value hash, includes also requested but non-existing properties
      */
     public function getProperties(array $keys): array
     {
         $props = array_fill_keys($keys, null);
 
         $this->properties()->whereIn('key', $keys)->get()
             ->each(function ($prop) use (&$props) {
                 $props[$prop->key] = $prop->value;
             });
 
         return $props;
     }
 
     /**
      * Remove a property
      *
      * @param string $key Property name
      */
     public function removeProperty(string $key): void
     {
         $this->setProperty($key, null);
     }
 
     /**
      * Create or update a property.
      *
      * @param string      $key   Property name
      * @param string|null $value The new value for the property
      */
     public function setProperty(string $key, $value): void
     {
         $this->storeProperty($key, $value);
     }
 
     /**
      * Create or update multiple properties in one fell swoop.
      *
      * @param array $data An associative array of key value pairs.
      */
     public function setProperties(array $data = []): void
     {
         foreach ($data as $key => $value) {
             $this->storeProperty($key, $value);
         }
     }
 
     /**
      * Create or update a property.
      *
      * @param string      $key   Property name
      * @param string|null $value The new value for the property
      */
     private function storeProperty(string $key, $value): void
     {
         if ($value === null || $value === '') {
             // Note: We're selecting the record first, so observers can act
             if ($prop = $this->properties()->where('key', $key)->first()) {
                 $prop->delete();
             }
         } else {
             $this->properties()->updateOrCreate(
                 ['key' => $key],
                 ['value' => $value]
             );
         }
     }
-
-    /**
-     * The user to which this item belongs.
-     *
-     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
-     */
-    public function user()
-    {
-        return $this->belongsTo(User::class, 'user_id', 'id');
-    }
 }
diff --git a/src/app/Mail/PasswordReset.php b/src/app/Mail/PasswordReset.php
index 889301be..51338efc 100644
--- a/src/app/Mail/PasswordReset.php
+++ b/src/app/Mail/PasswordReset.php
@@ -1,86 +1,87 @@
 <?php
 
 namespace App\Mail;
 
 use App\Tenant;
 use App\User;
 use App\Utils;
 use App\VerificationCode;
 use Illuminate\Bus\Queueable;
 use Illuminate\Mail\Mailable;
 use Illuminate\Queue\SerializesModels;
 use Illuminate\Support\Str;
 
 class PasswordReset extends Mailable
 {
     use Queueable;
     use SerializesModels;
 
     /** @var \App\VerificationCode A verification code object */
     protected $code;
 
 
     /**
      * Create a new message instance.
      *
      * @param \App\VerificationCode $code A verification code object
      *
      * @return void
      */
     public function __construct(VerificationCode $code)
     {
         $this->code = $code;
     }
 
     /**
      * Build the message.
      *
      * @return $this
      */
     public function build()
     {
         $appName = Tenant::getConfig($this->code->user->tenant_id, 'app.name');
         $supportUrl = Tenant::getConfig($this->code->user->tenant_id, 'app.support_url');
 
         $href = Utils::serviceUrl(
             sprintf('/password-reset/%s-%s', $this->code->short_code, $this->code->code),
             $this->code->user->tenant_id
         );
 
         $this->view('emails.html.password_reset')
             ->text('emails.plain.password_reset')
             ->subject(\trans('mail.passwordreset-subject', ['site' => $appName]))
             ->with([
                     'site' => $appName,
                     'code' => $this->code->code,
                     'short_code' => $this->code->short_code,
                     'link' => sprintf('<a href="%s">%s</a>', $href, $href),
                     'username' => $this->code->user->name(true)
             ]);
 
         return $this;
     }
 
     /**
      * Render the mail template with fake data
      *
      * @param string $type Output format ('html' or 'text')
      *
      * @return string HTML or Plain Text output
      */
     public static function fakeRender(string $type = 'html'): string
     {
         $code = new VerificationCode([
                 'code' => Str::random(VerificationCode::CODE_LENGTH),
                 'short_code' => VerificationCode::generateShortCode(),
         ]);
 
+        // @phpstan-ignore-next-line
         $code->user = new User([
               'email' => 'test@' . \config('app.domain'),
         ]);
 
         $mail = new self($code);
 
         return Helper::render($mail, $type);
     }
 }
diff --git a/src/app/Policy/RateLimit.php b/src/app/Policy/RateLimit.php
index 7605da4b..70f2c720 100644
--- a/src/app/Policy/RateLimit.php
+++ b/src/app/Policy/RateLimit.php
@@ -1,27 +1,25 @@
 <?php
 
 namespace App\Policy;
 
+use App\Traits\BelongsToUserTrait;
 use Illuminate\Database\Eloquent\Model;
 
 class RateLimit extends Model
 {
+    use BelongsToUserTrait;
+
     protected $fillable = [
         'user_id',
         'owner_id',
         'recipient_hash',
         'recipient_count'
     ];
 
     protected $table = 'policy_ratelimit';
 
     public function owner()
     {
-        $this->belongsTo('App\User');
-    }
-
-    public function user()
-    {
-        $this->belongsTo('App\User');
+        $this->belongsTo(\App\User::class);
     }
 }
diff --git a/src/app/SignupInvitation.php b/src/app/SignupInvitation.php
index d5f5ea68..2d353b4c 100644
--- a/src/app/SignupInvitation.php
+++ b/src/app/SignupInvitation.php
@@ -1,87 +1,78 @@
 <?php
 
 namespace App;
 
 use Carbon\Carbon;
 use Illuminate\Database\Eloquent\Model;
 use App\Traits\BelongsToTenantTrait;
+use App\Traits\BelongsToUserTrait;
 use App\Traits\UuidStrKeyTrait;
 
 /**
  * The eloquent definition of a signup invitation.
  *
- * @property string       $email
- * @property string       $id
- * @property ?int         $tenant_id
- * @property ?\App\Tenant $tenant
- * @property ?\App\User   $user
+ * @property string   $email
+ * @property string   $id
+ * @property ?int     $tenant_id
+ * @property ?int     $user_id
  */
 class SignupInvitation extends Model
 {
     use BelongsToTenantTrait;
+    use BelongsToUserTrait;
     use UuidStrKeyTrait;
 
     // just created
     public const STATUS_NEW     = 1 << 0;
     // it's been sent successfully
     public const STATUS_SENT    = 1 << 1;
     // sending failed
     public const STATUS_FAILED  = 1 << 2;
     // the user signed up
     public const STATUS_COMPLETED = 1 << 3;
 
 
     /** @var array<int, string> The attributes that are mass assignable */
     protected $fillable = ['email'];
 
 
     /**
      * Returns whether this invitation process completed (user signed up)
      *
      * @return bool
      */
     public function isCompleted(): bool
     {
         return ($this->status & self::STATUS_COMPLETED) > 0;
     }
 
     /**
      * Returns whether this invitation sending failed.
      *
      * @return bool
      */
     public function isFailed(): bool
     {
         return ($this->status & self::STATUS_FAILED) > 0;
     }
 
     /**
      * Returns whether this invitation is new.
      *
      * @return bool
      */
     public function isNew(): bool
     {
         return ($this->status & self::STATUS_NEW) > 0;
     }
 
     /**
      * Returns whether this invitation has been sent.
      *
      * @return bool
      */
     public function isSent(): bool
     {
         return ($this->status & self::STATUS_SENT) > 0;
     }
-
-    /**
-     * The account to which the invitation was used for.
-     *
-     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
-     */
-    public function user()
-    {
-        return $this->belongsTo(User::class, 'user_id', 'id');
-    }
 }
diff --git a/src/app/Traits/BelongsToUserTrait.php b/src/app/Traits/BelongsToUserTrait.php
new file mode 100644
index 00000000..25b9e9c8
--- /dev/null
+++ b/src/app/Traits/BelongsToUserTrait.php
@@ -0,0 +1,16 @@
+<?php
+
+namespace App\Traits;
+
+trait BelongsToUserTrait
+{
+    /**
+     * The user to which this object belongs.
+     *
+     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
+     */
+    public function user()
+    {
+        return $this->belongsTo(\App\User::class);
+    }
+}
diff --git a/src/app/UserAlias.php b/src/app/UserAlias.php
index 1f744626..d63cb1bf 100644
--- a/src/app/UserAlias.php
+++ b/src/app/UserAlias.php
@@ -1,38 +1,31 @@
 <?php
 
 namespace App;
 
+use App\Traits\BelongsToUserTrait;
 use Illuminate\Database\Eloquent\Model;
 
 /**
  * A email address alias for a User.
  *
  * @property string $alias
  * @property int    $id
  * @property int    $user_id
  */
 class UserAlias extends Model
 {
+    use BelongsToUserTrait;
+
     /** @var array<int, string> The attributes that are mass assignable */
     protected $fillable = ['user_id', 'alias'];
 
     /**
      * Ensure the email address is appropriately cased.
      *
      * @param string $alias Email address
      */
     public function setAliasAttribute(string $alias)
     {
         $this->attributes['alias'] = \strtolower($alias);
     }
-
-    /**
-     * The user to which this alias belongs.
-     *
-     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
-     */
-    public function user()
-    {
-        return $this->belongsTo(User::class, 'user_id', 'id');
-    }
 }
diff --git a/src/app/UserPassword.php b/src/app/UserPassword.php
index 7766d07b..af004420 100644
--- a/src/app/UserPassword.php
+++ b/src/app/UserPassword.php
@@ -1,39 +1,32 @@
 <?php
 
 namespace App;
 
+use App\Traits\BelongsToUserTrait;
 use Illuminate\Database\Eloquent\Model;
 
 /**
  * A password history entry of a User.
  *
  * @property int    $id
  * @property int    $user_id
  * @property string $password
  */
 class UserPassword extends Model
 {
+    use BelongsToUserTrait;
+
     /** @var bool Indicates if the model should be timestamped. */
     public $timestamps = false;
 
     /** @var array<string, string> The attributes that should be cast. */
     protected $casts = [
         'created_at' => 'datetime:Y-m-d H:i:s',
     ];
 
     /** @var array<int, string> The attributes that are mass assignable. */
     protected $fillable = ['user_id', 'password'];
 
     /** @var array<int, string> The attributes that should be hidden for arrays. */
     protected $hidden = ['password'];
-
-    /**
-     * The user to which this entry belongs.
-     *
-     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
-     */
-    public function user()
-    {
-        return $this->belongsTo(User::class, 'user_id', 'id');
-    }
 }
diff --git a/src/app/UserSetting.php b/src/app/UserSetting.php
index 3d3c2f80..83bf950e 100644
--- a/src/app/UserSetting.php
+++ b/src/app/UserSetting.php
@@ -1,29 +1,22 @@
 <?php
 
 namespace App;
 
+use App\Traits\BelongsToUserTrait;
 use Illuminate\Database\Eloquent\Model;
 
 /**
  * A collection of settings for a User.
  *
  * @property int    $id
  * @property int    $user_id
  * @property string $key
  * @property string $value
  */
 class UserSetting extends Model
 {
+    use BelongsToUserTrait;
+
     /** @var array<int, string> The attributes that are mass assignable */
     protected $fillable = ['user_id', 'key', 'value'];
-
-    /**
-     * The user to which this setting belongs.
-     *
-     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
-     */
-    public function user()
-    {
-        return $this->belongsTo(User::class, 'user_id', 'id');
-    }
 }
diff --git a/src/app/VerificationCode.php b/src/app/VerificationCode.php
index 13544011..6a07ee0c 100644
--- a/src/app/VerificationCode.php
+++ b/src/app/VerificationCode.php
@@ -1,83 +1,75 @@
 <?php
 
 namespace App;
 
+use App\Traits\BelongsToUserTrait;
 use Carbon\Carbon;
 use Illuminate\Database\Eloquent\Model;
 
 /**
  * The eloquent definition of a VerificationCode
  *
  * @property bool           $active      Active status
  * @property string         $code        The code
  * @property \Carbon\Carbon $expires_at  Expiration date-time
  * @property string         $mode        Mode, e.g. password-reset
- * @property \App\User      $user        User object
  * @property int            $user_id     User identifier
  * @property string         $short_code  Short code
  */
 class VerificationCode extends Model
 {
+    use BelongsToUserTrait;
+
     // Code expires after so many hours
     public const SHORTCODE_LENGTH = 8;
 
     public const CODE_LENGTH = 32;
 
     // Code expires after so many hours
     public const CODE_EXP_HOURS = 8;
 
     /** @var string The primary key associated with the table */
     protected $primaryKey = 'code';
 
     /** @var bool Indicates if the IDs are auto-incrementing */
     public $incrementing = false;
 
     /** @var string The "type" of the auto-incrementing ID */
     protected $keyType = 'string';
 
     /** @var bool Indicates if the model should be timestamped */
     public $timestamps = false;
 
     /** @var array<string, string> Casts properties as type */
     protected $casts = [
         'active' => 'boolean',
         'expires_at' => 'datetime',
     ];
 
     /** @var array<int, string> The attributes that are mass assignable */
     protected $fillable = ['user_id', 'code', 'short_code', 'mode', 'expires_at', 'active'];
 
 
     /**
      * Generate a short code (for human).
      *
      * @return string
      */
     public static function generateShortCode(): string
     {
         $code_length = env('VERIFICATION_CODE_LENGTH', self::SHORTCODE_LENGTH);
 
         return \App\Utils::randStr($code_length);
     }
 
     /**
      * Check if code is expired.
      *
      * @return bool True if code is expired, False otherwise
      */
     public function isExpired()
     {
         // @phpstan-ignore-next-line
         return $this->expires_at ? Carbon::now()->gte($this->expires_at) : false;
     }
-
-    /**
-     * The user to which this code belongs.
-     *
-     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
-     */
-    public function user()
-    {
-        return $this->belongsTo(User::class, 'user_id', 'id');
-    }
 }
diff --git a/src/tests/Unit/Mail/PasswordResetTest.php b/src/tests/Unit/Mail/PasswordResetTest.php
index 95a1bba2..ddc5554b 100644
--- a/src/tests/Unit/Mail/PasswordResetTest.php
+++ b/src/tests/Unit/Mail/PasswordResetTest.php
@@ -1,47 +1,48 @@
 <?php
 
 namespace Tests\Unit\Mail;
 
 use App\Mail\PasswordReset;
 use App\User;
 use App\Utils;
 use App\VerificationCode;
 use Tests\TestCase;
 
 class PasswordResetTest extends TestCase
 {
     /**
      * Test email content
      */
     public function testBuild(): void
     {
         $code = new VerificationCode([
                 'user_id' => 123456789,
                 'mode' => 'password-reset',
                 'code' => 'code',
                 'short_code' => 'short-code',
         ]);
 
+        // @phpstan-ignore-next-line
         $code->user = new User([
                 'name' => 'User Name',
         ]);
 
         $mail = $this->renderMail(new PasswordReset($code));
 
         $html = $mail['html'];
         $plain = $mail['plain'];
 
         $url = Utils::serviceUrl('/password-reset/' . $code->short_code . '-' . $code->code);
         $link = "<a href=\"$url\">$url</a>";
         $appName = \config('app.name');
 
         $this->assertSame("$appName Password Reset", $mail['subject']);
 
         $this->assertStringStartsWith('<!DOCTYPE html>', $html);
         $this->assertTrue(strpos($html, $link) > 0);
         $this->assertTrue(strpos($html, $code->user->name(true)) > 0);
 
         $this->assertStringStartsWith("Dear " . $code->user->name(true), $plain);
         $this->assertTrue(strpos($plain, $link) > 0);
     }
 }