 <p>The answer provided by @patricus above is absolutely correct, however, if like me <strong>you're looking to also benefit from casting out from JSON-encoded strings inside a pivot table</strong> then read on.</p> <h2>The Problem</h2> <p>I believe that there's a bug in Laravel at this stage. The problem is that when you instantiate a pivot model, it uses the native Illuminate-Model <code>setAttributes</code> method to "copy" the values of the pivot record table over to the pivot model.</p> <p>This is fine for most attributes, but gets sticky when it sees the <code>$casts</code> array contains a JSON-style cast - it actually double-encodes the data.</p> <h2>A Solution</h2> <p>The way I overcame this is as follows:</p> <p><strong>1. Set up your own Pivot base class from which to extend your pivot subclasses</strong> (more on this in a bit)</p> <p><strong>2. In your new Pivot base class, redefine the <code>setAttribute</code> method, commenting out the lines that handle JSON-castable attributes</strong></p> <pre><code>class MyPivot extends Pivot { public function setAttribute($key, $value) { if ($this-&gt;hasSetMutator($key)) { $method = 'set'.studly_case($key).'Attribute'; return $this-&gt;{$method}($value); } elseif (in_array($key, $this-&gt;getDates()) &amp;&amp; $value) { $value = $this-&gt;fromDateTime($value); } /* if ($this-&gt;isJsonCastable($key)) { $value = json_encode($value); } */ $this-&gt;attributes[$key] = $value; } } </code></pre> <p>This highlights the removal of the <code>isJsonCastable</code> method call, which will return <code>true</code> for any attributes you have casted as <code>json</code>, <code>array</code>, <code>object</code> or <code>collection</code> in your whizzy pivot subclasses.</p> <p><strong>3. Create your pivot subclasses using some sort of useful naming convention</strong> (I do <code>{PivotTable}Pivot</code> e.g. FeatureProductPivot)</p> <p><strong>4. In your base model class, change/create your <code>newPivot</code> method override to something a little more useful</strong></p> <p>Mine looks like this:</p> <pre><code>public function newPivot(Model $parent, array $attributes, $table, $exists) { $class = 'App\Models\\' . studly_case($table) . 'Pivot'; if ( class_exists( $class ) ) { return new $class($parent, $attributes, $table, $exists); } else { return parent::newPivot($parent, $attributes, $table, $exists); } } </code></pre> <p>Then just make sure you Models extend from your base model and you create your pivot-table "models" to suit your naming convention and voilà you will have working JSON casts on pivot table columns on the way out of the DB!</p> <p><strong>NB: This hasn't been thoroughly tested and may have problems saving back to the DB.</strong></p>