diff --git a/roofit/roofit/inc/RooJeffreysPrior.h b/roofit/roofit/inc/RooJeffreysPrior.h
index 8326079a1b199ded312b4fd02484ac7061998dbe..7c5177db01dcb7521b817a88ffaba2191ec634c3 100644
--- a/roofit/roofit/inc/RooJeffreysPrior.h
+++ b/roofit/roofit/inc/RooJeffreysPrior.h
@@ -17,7 +17,7 @@ class RooArgList ;
 class RooJeffreysPrior : public RooAbsPdf {
 public:
 
-  RooJeffreysPrior() ;
+  RooJeffreysPrior() { };
   RooJeffreysPrior(const char *name, const char *title, RooAbsPdf& nominal, const RooArgList& paramSet, const RooArgList& obsSet) ;
   virtual ~RooJeffreysPrior() ;
 
@@ -27,22 +27,31 @@ public:
   const RooArgList& lowList() const { return _obsSet ; }
   const RooArgList& paramList() const { return _paramSet ; }
 
-  Int_t getAnalyticalIntegral(RooArgSet& allVars, RooArgSet& analVars, const char* rangeName=0) const ;
-  Double_t analyticalIntegral(Int_t code, const char* rangeName=0) const ;
-
 protected:
 
-  RooRealProxy _nominal;           // The nominal value
-  //RooAbsPdf* _nominal;           // The nominal value
-  RooArgList   _ownedList ;       // List of owned components
-  RooListProxy _obsSet ;            // Low-side variation
-  RooListProxy _paramSet ;            // interpolation parameters
-  mutable TIterator* _paramIter ;  //! Iterator over paramSet
-  mutable TIterator* _obsIter ;  //! Iterator over lowSet
+  RooPdfProxy _nominal;    // Proxy to the PDF for this prior.
+  RooListProxy _obsSet ;   // Observables of the PDF.
+  RooListProxy _paramSet ; // Parameters of the PDF.
 
   Double_t evaluate() const;
 
-  ClassDef(RooJeffreysPrior,1) // Sum of RooAbsReal objects
+private:
+  struct CacheElem : public RooAbsCacheElement {
+  public:
+      virtual ~CacheElem() = default;
+      // Payload
+      std::unique_ptr<RooAbsPdf> _pdf;
+      std::unique_ptr<RooArgSet> _pdfVariables;
+
+      virtual RooArgList containedArgs(Action) override {
+        RooArgList list(*_pdf);
+        list.add(*_pdfVariables, true);
+        return list;
+      }
+  };
+  mutable RooObjCacheManager _cacheMgr; //!
+
+  ClassDef(RooJeffreysPrior,2) // Sum of RooAbsReal objects
 };
 
 #endif
diff --git a/roofit/roofit/src/RooJeffreysPrior.cxx b/roofit/roofit/src/RooJeffreysPrior.cxx
index 7095346ec3dcdfc4a832874d672c91b00b454999..b604ac11a8f4c3cf3ada3e3fe1b4c2ad942123ee 100644
--- a/roofit/roofit/src/RooJeffreysPrior.cxx
+++ b/roofit/roofit/src/RooJeffreysPrior.cxx
@@ -1,17 +1,17 @@
 /** \class RooJeffreysPrior
 \ingroup Roofit
 
-RooJeffreysPrior
-**/
-
+Implementation of Jeffrey's prior. This class estimates the fisher information matrix by generating
+a binned Asimov dataset from the supplied PDFs, fitting it, retrieving the covariance matrix and inverting
+it. It returns the square root of the determinant of this matrix.
+Numerical integration is used to normalise. Since each integration step requires fits to be run,
+evaluating complicated PDFs may take long.
 
-#include "RooFit.h"
-
-#include "Riostream.h"
-#include "Riostream.h"
-#include <math.h>
+Check the tutorial rs302_JeffreysPriorDemo.C for a demonstration with a simple PDF.
+**/
 
 #include "RooJeffreysPrior.h"
+
 #include "RooAbsReal.h"
 #include "RooAbsPdf.h"
 #include "RooErrorHandler.h"
@@ -23,8 +23,7 @@ RooJeffreysPrior
 #include "RooFitResult.h"
 #include "RooNumIntConfig.h"
 #include "RooRealVar.h"
-
-#include "TError.h"
+#include "RooHelpers.h"
 
 using namespace std;
 
@@ -33,54 +32,44 @@ ClassImp(RooJeffreysPrior);
 using namespace RooFit;
 
 ////////////////////////////////////////////////////////////////////////////////
-///_obsSet("!obsSet","obs-side variation",this),
+/// Construct a new JeffreysPrior.
+/// \param[in] name     Name of this object.
+/// \param[in] title    Title (for plotting)
+/// \param[in] nominal  The PDF to base Jeffrey's prior on.
+/// \param[in] paramSet Parameters of the PDF.
+/// \param[in] obsSet   Observables of the PDF.
 
 RooJeffreysPrior::RooJeffreysPrior(const char* name, const char* title,
               RooAbsPdf& nominal,
               const RooArgList& paramSet,
               const RooArgList& obsSet) :
   RooAbsPdf(name, title),
-  _nominal("nominal","nominal",this,nominal,kFALSE,kFALSE),
-  _obsSet("!obsSet","obs-side variation",this,kFALSE,kFALSE),
-  _paramSet("!paramSet","high-side variation",this)
+  _nominal("nominal","nominal",this, nominal, false, false),
+  _obsSet("!obsSet","Observables",this, false, false),
+  _paramSet("!paramSet","Parameters",this),
+  _cacheMgr(this, 1, true, false)
 {
-  _obsIter = _obsSet.createIterator() ;
-  _paramIter = _paramSet.createIterator() ;
-
-
-  TIterator* inputIter1 = obsSet.createIterator() ;
-  RooAbsArg* comp ;
-  while((comp = (RooAbsArg*)inputIter1->Next())) {
+  for (const auto comp : obsSet) {
     if (!dynamic_cast<RooAbsReal*>(comp)) {
       coutE(InputArguments) << "RooJeffreysPrior::ctor(" << GetName() << ") ERROR: component " << comp->GetName()
-             << " in first list is not of type RooAbsReal" << endl ;
+             << " in observable list is not of type RooAbsReal" << endl ;
       RooErrorHandler::softAbort() ;
     }
     _obsSet.add(*comp) ;
-    //    if (takeOwnership) {
-    //      _ownedList.addOwned(*comp) ;
-    //    }
   }
-  delete inputIter1 ;
 
-  TIterator* inputIter3 = paramSet.createIterator() ;
-  while((comp = (RooAbsArg*)inputIter3->Next())) {
+  for (const auto comp : paramSet) {
     if (!dynamic_cast<RooAbsReal*>(comp)) {
       coutE(InputArguments) << "RooJeffreysPrior::ctor(" << GetName() << ") ERROR: component " << comp->GetName()
-             << " in first list is not of type RooAbsReal" << endl ;
+             << " in parameter list is not of type RooAbsReal" << endl ;
       RooErrorHandler::softAbort() ;
     }
     _paramSet.add(*comp) ;
-    //    if (takeOwnership) {
-    //      _ownedList.addOwned(*comp) ;
-    //    }
   }
-  delete inputIter3 ;
 
   // use a different integrator by default.
   if(paramSet.getSize()==1)
     this->specialIntegratorConfig(kTRUE)->method1D().setLabel("RooAdaptiveGaussKronrodIntegrator1D")  ;
-
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -90,21 +79,9 @@ RooJeffreysPrior::RooJeffreysPrior(const RooJeffreysPrior& other, const char* na
   RooAbsPdf(other, name),
   _nominal("!nominal",this,other._nominal),
   _obsSet("!obsSet",this,other._obsSet),
-  _paramSet("!paramSet",this,other._paramSet)
-{
-  _obsIter = _obsSet.createIterator() ;
-  _paramIter = _paramSet.createIterator() ;
-
-  // Member _ownedList is intentionally not copy-constructed -- ownership is not transferred
-}
-
-////////////////////////////////////////////////////////////////////////////////
-/// Default constructor
-
-RooJeffreysPrior::RooJeffreysPrior()
+  _paramSet("!paramSet",this,other._paramSet),
+  _cacheMgr(this, 1, true, false)
 {
-  _obsIter = NULL;
-  _paramIter = NULL;
 
 }
 
@@ -113,8 +90,7 @@ RooJeffreysPrior::RooJeffreysPrior()
 
 RooJeffreysPrior::~RooJeffreysPrior()
 {
-  if (_obsIter) delete _obsIter ;
-  if (_paramIter) delete _paramIter ;
+
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -122,65 +98,41 @@ RooJeffreysPrior::~RooJeffreysPrior()
 
 Double_t RooJeffreysPrior::evaluate() const
 {
-  RooFit::MsgLevel msglevel = RooMsgService::instance().globalKillBelow();
-  RooMsgService::instance().setGlobalKillBelow(RooFit::WARNING);
-  // create Asimov dataset
-  //  _paramSet.Print("v");
-  //  return sqrt(_paramSet.getRealValue("mu"));
-  *(_nominal.arg().getVariables()) = _paramSet;
-  /*
-  cout << "_______________"<<endl;
-  _paramSet.Print("v");
-  _nominal->getVariables()->Print("v");
-  cout << "_______________"<<endl;
-  */
-  RooDataHist* data = ((RooAbsPdf&)(_nominal.arg())).generateBinned(_obsSet,ExpectedData());
-  //  data->Print("v");
-  //RooFitResult* res = _nominal->fitTo(*data, Save(),PrintLevel(-1),Minos(kFALSE),SumW2Error(kTRUE));
-  RooFitResult* res = ((RooAbsPdf&)(_nominal.arg())).fitTo(*data, Save(),PrintLevel(-1),Minos(kFALSE),SumW2Error(kFALSE));
-  TMatrixDSym cov = res->covarianceMatrix();
-  cov.Invert();
-  double ret =  sqrt(cov.Determinant());
-
-  /*
-    // for 1 parameter can avoid making TMatrix etc.
-    // but number of params may be > 1 with others held constant
-  if(_paramSet.getSize()==1){
-    RooRealVar* var = (RooRealVar*) _paramSet.first();
-    // also, the _paramSet proxy one does not pick up a different value
-    cout << "eval at "<< ret << " " << 1/(var->getError()) << endl;
-    // need to get the actual variable instance out of the pdf like below
-    var = (RooRealVar*) _nominal->getVariables()->find(var->GetName());
-    cout << "eval at "<< ret << " " << 1/(var->getError()) << endl;
-  }
-  */
+  RooHelpers::LocalChangeMsgLevel msgLvlRAII(RooFit::WARNING);
+
+
+  CacheElem* cacheElm = (CacheElem*) _cacheMgr.getObj(nullptr);
+  if (!cacheElm) {
+    //Internally, we have to enlarge the range of fit parameters to make
+    //fits converge even if we are close to the limit of a parameter. Therefore, we clone the pdf and its
+    //observables here. If something happens to the external PDF, the cache is wiped,
+    //and we start to clone again.
+    auto& pdf = _nominal.arg();
+    RooAbsPdf* clonePdf = static_cast<RooAbsPdf*>(pdf.cloneTree());
+    auto vars = clonePdf->getParameters(_obsSet);
+    for (auto varTmp : *vars) {
+      auto& var = static_cast<RooRealVar&>(*varTmp);
+      auto range = var.getRange();
+      double span = range.second - range.first;
+      var.setRange(range.first - 0.1*span, range.second + 0.1 * span);
+    }
 
-  //  res->Print();
-  delete data;
-  delete res;
-  RooMsgService::instance().setGlobalKillBelow(msglevel);
+    cacheElm = new CacheElem;
+    cacheElm->_pdf.reset(clonePdf);
+    cacheElm->_pdfVariables.reset(vars);
 
-  //  cout << "eval at "<< ret << endl;
-  //  _paramSet.Print("v");
-  return ret;
+    _cacheMgr.setObj(nullptr, cacheElm);
+  }
 
-}
+  auto& cachedPdf = *cacheElm->_pdf;
+  auto& pdfVars = *cacheElm->_pdfVariables;
+  pdfVars = _paramSet;
 
-////////////////////////////////////////////////////////////////////////////////
-///  if (matchArgs(allVars,analVars,x)) return 1 ;
-///  if (matchArgs(allVars,analVars,mean)) return 2 ;
-///  return 1;
+  std::unique_ptr<RooDataHist> data( cachedPdf.generateBinned(_obsSet,ExpectedData()) );
+  std::unique_ptr<RooFitResult> res( cachedPdf.fitTo(*data, Save(),PrintLevel(-1),Minos(false),SumW2Error(false)) );
+  TMatrixDSym cov = res->covarianceMatrix();
+  cov.Invert();
 
-Int_t RooJeffreysPrior::getAnalyticalIntegral(RooArgSet& /*allVars*/, RooArgSet& /*analVars*/, const char* /*rangeName*/) const
-{
-  return 0 ;
+  return sqrt(cov.Determinant());
 }
 
-////////////////////////////////////////////////////////////////////////////////
-
-Double_t RooJeffreysPrior::analyticalIntegral(Int_t code, const char* /*rangeName*/) const
-{
-  R__ASSERT(code==1 );
-  //cout << "evaluating analytic integral" << endl;
-  return 1.;
-}
diff --git a/tutorials/roostats/JeffreysPriorDemo.C b/tutorials/roostats/rs302_JeffreysPriorDemo.C
similarity index 86%
rename from tutorials/roostats/JeffreysPriorDemo.C
rename to tutorials/roostats/rs302_JeffreysPriorDemo.C
index 0904ad8d5a1e027134c540992ea9484e42c01a49..c2f720a5f92e901a4a7dc711d794c5c0dcc79638 100644
--- a/tutorials/roostats/JeffreysPriorDemo.C
+++ b/tutorials/roostats/rs302_JeffreysPriorDemo.C
@@ -36,14 +36,16 @@
 #include "RooWorkspace.h"
 #include "RooDataHist.h"
 #include "RooGenericPdf.h"
-#include "TCanvas.h"
 #include "RooPlot.h"
 #include "RooFitResult.h"
-#include "TMatrixDSym.h"
 #include "RooRealVar.h"
 #include "RooAbsPdf.h"
 #include "RooNumIntConfig.h"
+
 #include "TH1F.h"
+#include "TCanvas.h"
+#include "TLegend.h"
+#include "TMatrixDSym.h"
 
 using namespace RooFit;
 
@@ -71,22 +73,24 @@ void JeffreysPriorDemo()
 
    RooJeffreysPrior pi("jeffreys", "jeffreys", *w.pdf("p"), *w.set("poi"), *w.set("obs"));
 
-   RooGenericPdf *test = new RooGenericPdf("test", "test", "1./sqrt(mu)", *w.set("poi"));
+   RooGenericPdf *test = new RooGenericPdf("Expected", "Expected = 1/#sqrt{#mu}", "1./sqrt(mu)",
+      *w.set("poi"));
 
    TCanvas *c1 = new TCanvas;
-   // The method to compute the Jeffreys prior becomes unstable at the boundaries.
-   // Therefore, we don't plot it all the way.
-   RooPlot *plot = w.var("mu")->frame(Range(2, 199));
+   RooPlot *plot = w.var("mu")->frame();
    pi.plotOn(plot);
-   test->plotOn(plot, LineColor(kRed));
+   test->plotOn(plot, LineColor(kRed), LineStyle(kDashDotted));
    plot->Draw();
+   
+   auto legend = plot->BuildLegend();
+   legend->DrawClone();
 }
 
 //_________________________________________________
 void TestJeffreysGaussMean()
 {
    RooWorkspace w("w");
-   w.factory("Gaussian::g(x[0,-20,20],mu[0,-5,5],sigma[1,0,10])");
+   w.factory("Gaussian::g(x[0,-20,20],mu[0,-5.,5],sigma[1,0,10])");
    w.factory("n[10,.1,200]");
    w.factory("ExtendPdf::p(g,n)");
    w.var("sigma")->setConstant();
@@ -113,13 +117,16 @@ void TestJeffreysGaussMean()
    pi.getParameters(*temp)->Print();
 
    //  return;
-   RooGenericPdf *test = new RooGenericPdf("test", "test", "1", *w.set("poi"));
+   RooGenericPdf *test = new RooGenericPdf("constant", "Expected = constant", "1", *w.set("poi"));
 
    TCanvas *c1 = new TCanvas;
    RooPlot *plot = w.var("mu")->frame();
    pi.plotOn(plot);
-   test->plotOn(plot, LineColor(kRed), LineStyle(kDotted));
+   test->plotOn(plot, LineColor(kRed), LineStyle(kDashDotted));
    plot->Draw();
+   
+   auto legend = plot->BuildLegend();
+   legend->DrawClone();
 }
 
 //_________________________________________________
@@ -159,13 +166,16 @@ void TestJeffreysGaussSigma()
    const RooArgSet *temp = w.set("poi");
    pi.getParameters(*temp)->Print();
 
-   RooGenericPdf *test = new RooGenericPdf("test", "test", "sqrt(2.)/sigma", *w.set("poi"));
+   RooGenericPdf *test = new RooGenericPdf("test", "Expected = #sqrt{2}/#sigma", "sqrt(2.)/sigma", *w.set("poi"));
 
    TCanvas *c1 = new TCanvas;
    RooPlot *plot = w.var("sigma")->frame();
    pi.plotOn(plot);
-   test->plotOn(plot, LineColor(kRed), LineStyle(kDotted));
+   test->plotOn(plot, LineColor(kRed), LineStyle(kDashDotted));
    plot->Draw();
+   
+   auto legend = plot->BuildLegend();
+   legend->DrawClone();
 }
 
 //_________________________________________________
@@ -177,7 +187,7 @@ void TestJeffreysGaussMeanAndSigma()
    // if the Gaussian is too wide range(x) ~ sigma then PDF gets renormalized
    //   and the PDF falls off too fast at high sigma
    RooWorkspace w("w");
-   w.factory("Gaussian::g(x[0,-20,20],mu[0,-5,5],sigma[1,1,5])");
+   w.factory("Gaussian::g(x[0,-20,20],mu[0,-5,5],sigma[1,1.,5.])");
    w.factory("n[100,.1,2000]");
    w.factory("ExtendPdf::p(g,n)");
 
@@ -206,6 +216,6 @@ void TestJeffreysGaussMeanAndSigma()
    //  return;
 
    TCanvas *c1 = new TCanvas;
-   TH1 *Jeff2d = pi.createHistogram("2dJeffreys", *w.var("mu"), Binning(10), YVar(*w.var("sigma"), Binning(10)));
+   TH1 *Jeff2d = pi.createHistogram("2dJeffreys", *w.var("mu"), Binning(10, -5., 5), YVar(*w.var("sigma"), Binning(10, 1., 5.)));
    Jeff2d->Draw("surf");
 }